青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

兔子的技術博客

兔子

   :: 首頁 :: 聯系 :: 聚合  :: 管理
  202 Posts :: 0 Stories :: 43 Comments :: 0 Trackbacks

留言簿(10)

最新評論

閱讀排行榜

評論排行榜

因為QTP的需要,同事寫了通過進程來調用Plink進行Telnet連接的接口。我測試的時候發現,他那個調用.Net 里面的Process進程的方法,通過重定向獲取標準輸出流的辦法有點不好,就是調用了流動Read()函數之后,就會一直阻塞在那里,知道流中有數據才能正確返回,而peek函數又不能正確的監測到流中是否有數據可以讀。我先去翻翻了MSDN中那個StreamReader類的辦法,好像確實沒有辦法,反倒是在Process的StandardOutput屬性的說明那里,明顯寫著,如果標準輸出里面沒有數據的話,read函數就會無限時的阻塞在那里知道有數據可以讀才行,然后他還提到了一些導致死鎖的問題。

我去寫了個簡單的.Net程序來測試了一下,可以知道那個StreamReader是一個FileStream來的,而且那個CanTimeout等屬性都表明不是一個可以異步讀取的流。難道真沒有辦法監測到這個流中是否有數據可讀的狀態嗎? 根據常識知道,這個流應該是“匿名管道”來的,去找了一下MSDN中關于管道的api函數,還真讓我找到了一個,那就是PeekNamedPipe http://msdn.microsoft.com/en-us/library/aa365779(VS.85).aspx

根據它的說明,來看看這個

The PeekNamedPipe function is similar to the ReadFile function with the following exceptions:

  • The data is read in the mode specified with CreateNamedPipe. For example, create a pipe with PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE. If you change the mode to PIPE_READMODE_BYTE with SetNamedPipeHandleStateReadFile will read in byte mode, but PeekNamedPipe will continue to read in message mode.
  • The data read from the pipe is not removed from the pipe's buffer.
  • The function can return additional information about the contents of the pipe.
  • The function always returns immediately in a single-threaded application, even if there is no data in the pipe. The wait mode of a named pipe handle (blocking or nonblocking) has no effect on the function.

Note   The PeekNamedPipe function can block thread execution the same way any I/O function can when called on a synchronous handle in a multi-threaded application. To avoid this condition, use a pipe handle created for asynchronous I/O.

If the specified handle is a named pipe handle in byte-read mode, the function reads all available bytes up to the size specified in nBufferSize. For a named pipe handle in message-read mode, the function reads the next message in the pipe. If the message is larger than nBufferSize, the function returns TRUE after reading the specified number of bytes. In this situation, lpBytesLeftThisMessage will receive the number of bytes remaining in the message.

這個函數不管命名管道是不是阻塞模式的,都會立即返回(除了在多線程環境下的某種情況下會阻塞,大概就是http://my.donews.com/yeyanbo/tag/peeknamedpipe/這個文章發現的問題。),文檔又說所有的”匿名管道“其實都是一個“命名管道”來實現的,所以操作“命名管道”的函數對“匿名管道”也是有效的。這個函數明顯是我想要的,可以用來檢測process標準輸出流中是否有數據可以讀,又不會阻塞。在vb.net的測試代碼里面試了一下,應該是可以工作,測試代碼如下:

Imports System.Diagnostics.Process
Public Class Form1
    
Declare Function SetNamedPipeHandleState Lib "kernel32" (ByVal hNamedPipe As IntegerByRef lpMode As IntegerByRef lpMaxCollectionCount As IntegerByRef lpCollectDataTimeout As IntegerAs Integer
    
Declare Function PeekNamedPipe Lib "kernel32" (ByVal hNamedPipe As IntegerByRef lpBuffer As IntegerByVal nBufferSize As IntegerByRef lpBytesRead As IntegerByRef lpTotalBytesAvail As IntegerByRef lpBytesLeftThisMessage As IntegerAs Integer
    
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        
Dim p As Process = New Process
        p.StartInfo.FileName 
= "c:\windows\system32\cmd.exe"
        p.StartInfo.RedirectStandardInput 
= True
        p.StartInfo.RedirectStandardOutput 
= True
        p.StartInfo.UseShellExecute 
= False
        p.Start()
        p.StandardInput.WriteLine(
"hostname")
        
Dim f As System.IO.FileStream = p.StandardOutput.BaseStream

        
Dim mode As Integer
        mode 
= 1 ' no-wait
        Dim count As Integer
        
'修改這個命名管道為 異步的,是不能成功的
        ''mode = SetNamedPipeHandleState(f.Handle, mode, System.IntPtr.Zero, System.IntPtr.Zero)
        '不過這個PeekNamePipe 函數是可以得到 管道里面有多少字節可以讀到,執行完之后count里面是對的,可以讀取的數據
        mode = PeekNamedPipe(f.Handle, System.IntPtr.Zero, 0, System.IntPtr.Zero, count, System.IntPtr.Zero)
        p.StandardOutput.Read()
        
While p.StandardOutput.Peek > 0
            p.StandardOutput.Read()
        
End While
        
'在這個地方的時候就不能再read了,read就無限阻塞直到有數據來才能返回了。
        mode = p.StandardOutput.Peek() '這個時候的peek返回 -1是對的
        mode = PeekNamedPipe(f.Handle, System.IntPtr.Zero, 0, System.IntPtr.Zero, count, System.IntPtr.Zero) '這個count得到0 是對的,管道里面沒有消息的了
        p.StandardInput.WriteLine("hostname")
        mode 
= p.StandardOutput.Peek() '這個還是返回 -1是不對的,
        mode = PeekNamedPipe(f.Handle, System.IntPtr.Zero, 0, System.IntPtr.Zero, count, System.IntPtr.Zero) '這個返回正確的count,表明管道里面有數據是對的
        p.StandardOutput.Read()
        p.StandardOutput.Peek() 
'peek函數一定要在read成功調用過一次之后才能正確的得到管道的狀態。但Read一次又可能引起無限時間的阻塞!!!!所以只有PeekNamedPipe才能正確的無阻塞的檢測到管道的數據
    End Sub
End Class

總結一下 :感覺。Net對這個“命名管道“”匿名管道“的支持明顯不夠,API中都有監測到管道是否有數據可以讀到函數。.Net里面卻連管道對應的類都沒有實現,所以相應的這種阻塞情況就也沒法處理了。可能這部分的封裝有待完善吧。

后來有用Reflector工具反匯編看了看系統Process幾個類的相應實現代碼,可以看到他是CreatePipe創建一個管道,然后DuplicateHandle復制了一個文件句柄的,跟我事先的猜測是一樣的。Linux的輸出重定向使用也要類似的這樣兩個步驟。如果你自己看他的代碼,可以看到創建的是一個只讀的、不支持異步的FileSteam來的,他代碼是這樣寫的:

public bool Start()
{
    
this.Close();
    ProcessStartInfo startInfo 
= this.StartInfo;
    
if (startInfo.FileName.Length == 0)
    {
        
throw new InvalidOperationException(SR.GetString("FileNameMissing"));
    }
    
if (startInfo.UseShellExecute)
    {
        
return this.StartWithShellExecuteEx(startInfo);
    }
    
return this.StartWithCreateProcess(startInfo);
}

private bool StartWithCreateProcess(ProcessStartInfo startInfo)
{
    
if ((startInfo.StandardOutputEncoding != null&& !startInfo.RedirectStandardOutput)
    {
        
throw new InvalidOperationException(SR.GetString("StandardOutputEncodingNotAllowed"));
    }
    
if ((startInfo.StandardErrorEncoding != null&& !startInfo.RedirectStandardError)
    {
        
throw new InvalidOperationException(SR.GetString("StandardErrorEncodingNotAllowed"));
    }
    
if (this.disposed)
    {
        
throw new ObjectDisposedException(base.GetType().Name);
    }
    StringBuilder cmdLine 
= BuildCommandLine(startInfo.FileName, startInfo.Arguments);
    NativeMethods.STARTUPINFO lpStartupInfo 
= new NativeMethods.STARTUPINFO();
    SafeNativeMethods.PROCESS_INFORMATION lpProcessInformation 
= new SafeNativeMethods.PROCESS_INFORMATION();
    SafeProcessHandle processHandle 
= new SafeProcessHandle();
    SafeThreadHandle handle2 
= new SafeThreadHandle();
    
int error = 0;
    SafeFileHandle parentHandle 
= null;
    SafeFileHandle handle4 
= null;
    SafeFileHandle handle5 
= null;
    GCHandle handle6 
= new GCHandle();
    
try
    {
        
bool flag;
        
if ((startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput) || startInfo.RedirectStandardError)
        {
            
if (startInfo.RedirectStandardInput)
            {
                
this.CreatePipe(out parentHandle, out lpStartupInfo.hStdInput, true);
            }
            
else
            {
                lpStartupInfo.hStdInput 
= new SafeFileHandle(NativeMethods.GetStdHandle(-10), false);
            }
            
if (startInfo.RedirectStandardOutput)
            {
                
this.CreatePipe(out handle4, out lpStartupInfo.hStdOutput, false);
            }
            
else
            {
                lpStartupInfo.hStdOutput 
= new SafeFileHandle(NativeMethods.GetStdHandle(-11), false);
            }


中間省略一部分

   if (startInfo.RedirectStandardInput)

    {
        this.standardInput = new StreamWriter(new FileStream(parentHandle, FileAccess.Write, 0x1000, false), Encoding.GetEncoding(NativeMethods.GetConsoleCP()), 0x1000);
        this.standardInput.AutoFlush = true;
    }
    if (startInfo.RedirectStandardOutput)
    {
        Encoding encoding = (startInfo.StandardOutputEncoding != null) ? startInfo.StandardOutputEncoding : Encoding.GetEncoding(NativeMethods.GetConsoleOutputCP());
        this.standardOutput = new StreamReader(new FileStream(handle4, FileAccess.Read, 0x1000, false), encoding, true, 0x1000);
    }
    if (startInfo.RedirectStandardError)
    {
        Encoding encoding2 = (startInfo.StandardErrorEncoding != null) ? startInfo.StandardErrorEncoding : Encoding.GetEncoding(NativeMethods.GetConsoleOutputCP());
        this.standardError = new StreamReader(new FileStream(handle5, FileAccess.Read, 0x1000, false), encoding2, true, 0x1000);
    }
    bool flag3 = false;
    if (!processHandle.IsInvalid)
    {
        this.SetProcessHandle(processHandle);
        this.SetProcessId(lpProcessInformation.dwProcessId);
        handle2.Close();
        flag3 = true;
    }
    return flag3;
}

private void CreatePipe(out SafeFileHandle parentHandle, out SafeFileHandle childHandle, bool parentInputs)
{
    NativeMethods.SECURITY_ATTRIBUTES lpPipeAttributes = new NativeMethods.SECURITY_ATTRIBUTES();
    lpPipeAttributes.bInheritHandle = true;
    SafeFileHandle hWritePipe = null;
    try
    {
        if (parentInputs)
        {
            CreatePipeWithSecurityAttributes(out childHandle, out hWritePipe, lpPipeAttributes, 0);
        }
        else
        {
            CreatePipeWithSecurityAttributes(out hWritePipe, out childHandle, lpPipeAttributes, 0);
        }
        if (!NativeMethods.DuplicateHandle(new HandleRef(this, NativeMethods.GetCurrentProcess()), hWritePipe, new HandleRef(this, NativeMethods.GetCurrentProcess()), out parentHandle, 0, false, 2))
        {
            throw new Win32Exception();
        }
    }
    finally
    {
        if ((hWritePipe != null) && !hWritePipe.IsInvalid)
        {
            hWritePipe.Close();
        }
    }
}

private static void CreatePipeWithSecurityAttributes(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe, NativeMethods.SECURITY_ATTRIBUTES lpPipeAttributes, int nSize)
{
    if ((!NativeMethods.CreatePipe(out hReadPipe, out hWritePipe, lpPipeAttributes, nSize) || hReadPipe.IsInvalid) || hWritePipe.IsInvalid)
    {
        throw new Win32Exception();
    }
}

public override int Peek()
{
    if (this.stream == null)
    {
        __Error.ReaderClosed();
    }
    if ((this.charPos != this.charLen) || (!this._isBlocked && (this.ReadBuffer() != 0)))
    {
        return this.charBuffer[this.charPos];
    }
    return -1;
}
轉自:http://hi.baidu.com/widebright/item/f58e2516a6bb41dcbf9042a4
posted on 2012-08-16 13:30 會飛的兔子 閱讀(4457) 評論(0)  編輯 收藏 引用 所屬分類: 系統API,底層技術
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲综合精品一区二区| 欧美日韩国产精品专区| 99国产精品国产精品久久| 亚洲综合成人在线| 欧美成人精品在线播放| 亚洲精品免费在线观看| 亚洲精品久久久久久久久久久 | 亚洲精品久久久久久久久久久| 午夜在线视频一区二区区别| 欧美理论大片| 亚洲美女黄色| 亚洲啪啪91| 国产精品vvv| 亚洲欧美日韩精品综合在线观看| 亚洲丰满少妇videoshd| 欧美1区2区3区| 亚洲精品国产精品乱码不99按摩 | 亚洲一本视频| 99爱精品视频| 国产乱码精品1区2区3区| 狼狼综合久久久久综合网| 久久av一区二区三区| 韩日精品在线| 欧美激情精品久久久久| 欧美日韩视频免费播放| 久久久久久电影| 欧美精品在线免费播放| 欧美一区中文字幕| 老司机一区二区三区| 狠狠色2019综合网| 性欧美精品高清| 老色鬼久久亚洲一区二区| 亚洲曰本av电影| 欧美精品九九99久久| 久久久高清一区二区三区| 国产精品免费电影| 亚洲综合首页| 久久九九免费视频| 国内精品国产成人| 亚洲一二三区精品| 欧美精品电影| 亚洲美女黄网| 亚洲一区视频| 国产区在线观看成人精品| 久久精品一区二区三区不卡| 亚洲日本乱码在线观看| 亚洲免费视频在线观看| 中文日韩电影网站| 国产精品网站在线| 欧美一区二区三区四区高清| 免费观看成人www动漫视频| 亚洲精品美女久久7777777| 亚洲乱码精品一二三四区日韩在线| 欧美阿v一级看视频| 亚洲精品久久7777| 99热免费精品在线观看| 欧美日韩一区在线播放| 亚洲精品久久视频| 亚洲成色精品| 欧美激情一区二区三区高清视频| 中文av字幕一区| 欧美jizz19性欧美| 亚洲福利av| 欧美中文日韩| 亚洲视频一区在线观看| 欧美成人午夜激情| 久久国产婷婷国产香蕉| 日韩午夜高潮| 一区二区三区在线免费播放| 欧美午夜精品久久久| 久久国产精品电影| 一本一本久久a久久精品综合麻豆| 久久久免费精品视频| 最近中文字幕日韩精品 | 国产精品每日更新| 亚洲婷婷在线| 亚洲成色777777女色窝| 国产欧美精品在线| 欧美视频一区二区三区| 久久五月婷婷丁香社区| 性久久久久久久久久久久| 亚洲精品三级| 亚洲精品国产精品乱码不99 | 国内成+人亚洲| 国产精品激情| 国产精品久久久久9999| 国产精品vvv| 国产伦理精品不卡| 国产农村妇女精品一区二区| 国产精品免费视频xxxx| 欧美国产国产综合| 欧美日韩在线第一页| 裸体女人亚洲精品一区| 一区二区黄色| 亚洲免费视频在线观看| 亚洲欧美99| 老司机免费视频一区二区| 欧美激情综合在线| 国产精品区二区三区日本 | 久久伊人亚洲| 亚洲高清毛片| 亚洲影视综合| 久久综合国产精品台湾中文娱乐网| 免费成人av在线| 国产精品福利av| 亚洲电影第三页| 午夜激情久久久| 亚洲人成亚洲人成在线观看| 欧美va亚洲va国产综合| 久久精品国产综合精品| 欧美视频在线免费| 伊人色综合久久天天| 夜夜狂射影院欧美极品| 久久免费国产| 午夜免费日韩视频| 欧美日韩精品高清| 国内精品久久久| 亚洲综合清纯丝袜自拍| 欧美国产综合| 久久综合色播五月| 国产亚洲一二三区| 午夜亚洲福利在线老司机| 9l国产精品久久久久麻豆| 欧美成人免费在线视频| 亚洲精品久久久久| 亚洲国产成人不卡| 久久久久国色av免费观看性色| 老巨人导航500精品| 亚洲第一在线| 亚洲欧洲一级| 欧美日韩一二区| 香蕉久久夜色| 欧美在线观看www| 亚洲美女在线一区| 亚洲欧洲三级| 国产视频久久久久| 两个人的视频www国产精品| 久久综合福利| 亚洲欧美国产日韩中文字幕| 亚洲欧美日韩国产精品| 国产一区二区黄| 麻豆成人小视频| 欧美电影免费| 午夜伦理片一区| 欧美承认网站| 久久精品一区蜜桃臀影院| 亚洲欧美中日韩| 欧美日韩视频不卡| 免费欧美日韩| 欧美视频四区| 亚洲第一精品电影| 国产精品日韩在线观看| 欧美11—12娇小xxxx| 国产欧美日韩三区| 亚洲精品国久久99热| 久久亚洲一区二区| 久久久人人人| 亚洲在线国产日韩欧美| 另类av一区二区| 欧美在线视频免费播放| 国产精品久99| 宅男精品导航| 亚洲特黄一级片| 欧美视频一二三区| 9l视频自拍蝌蚪9l视频成人| 亚洲激情第一页| 久久久久久久性| 欧美国产日韩一区二区在线观看 | 激情视频一区二区| 免费亚洲网站| 亚洲欧美一级二级三级| 欧美激情一区二区久久久| 国产精品99久久久久久人 | 久久久久亚洲综合| 99国产精品99久久久久久粉嫩| 欧美亚洲第一区| 久久国产精品电影| 一区二区三区**美女毛片 | 一本色道久久88综合亚洲精品ⅰ| 亚洲欧美精品伊人久久| 亚洲精品欧美激情| 国产欧美一区二区精品忘忧草| 玖玖玖免费嫩草在线影院一区| 一区二区三区**美女毛片| 鲁大师影院一区二区三区| 亚洲视频观看| 最近看过的日韩成人| 国内一区二区三区| 国产精品一区免费在线观看| 欧美日韩精品在线| 欧美成人一区二区三区片免费| 久久久www成人免费精品| 亚洲男同1069视频| 亚洲欧美另类中文字幕| 一区二区三区精品视频| 最新日韩av| 亚洲黄色成人| 亚洲老板91色精品久久| 亚洲青涩在线| 亚洲第一偷拍|