• <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>

            兔子的技術(shù)博客

            兔子

               :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
              202 Posts :: 0 Stories :: 43 Comments :: 0 Trackbacks

            留言簿(10)

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

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

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

            根據(jù)它的說明,來看看這個(gè)

            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.

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

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

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

            后來有用Reflector工具反匯編看了看系統(tǒng)Process幾個(gè)類的相應(yīng)實(shí)現(xiàn)代碼,可以看到他是CreatePipe創(chuàng)建一個(gè)管道,然后DuplicateHandle復(fù)制了一個(gè)文件句柄的,跟我事先的猜測是一樣的。Linux的輸出重定向使用也要類似的這樣兩個(gè)步驟。如果你自己看他的代碼,可以看到創(chuàng)建的是一個(gè)只讀的、不支持異步的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;
            }
            轉(zhuǎn)自:http://hi.baidu.com/widebright/item/f58e2516a6bb41dcbf9042a4
            posted on 2012-08-16 13:30 會(huì)飛的兔子 閱讀(4434) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 系統(tǒng)API,底層技術(shù)
            亚洲国产精品狼友中文久久久| 精品欧美一区二区三区久久久| 亚洲一区中文字幕久久| 久久婷婷国产麻豆91天堂| 久久久久国产亚洲AV麻豆| 久久99精品久久久大学生| 久久精品这里热有精品| 久久久久久无码国产精品中文字幕 | 久久久亚洲精品蜜桃臀| 99久久精品免费看国产一区二区三区| 亚洲AV日韩AV天堂久久| 国产亚洲精久久久久久无码AV| 亚洲国产精品狼友中文久久久 | 久久人人爽人人爽人人片AV麻豆 | 久久香蕉国产线看观看精品yw| 久久久久久亚洲精品无码| 久久久久久久久久久精品尤物| 久久综合九色综合久99 | 久久国产综合精品五月天| 日韩乱码人妻无码中文字幕久久| 国产精品亚洲综合专区片高清久久久| 国内精品伊人久久久久AV影院| 亚洲欧美精品一区久久中文字幕 | 久久精品国产亚洲AV大全| 亚洲va久久久噜噜噜久久| 久久久久人妻一区精品果冻| 久久91精品国产91久久户| 伊人丁香狠狠色综合久久| 久久精品国产亚洲AV香蕉| 久久精品国产清自在天天线 | 久久婷婷五月综合97色直播| 老司机午夜网站国内精品久久久久久久久| 久久精品国产99国产电影网| 天天爽天天狠久久久综合麻豆| 亚洲精品无码久久不卡| 久久久中文字幕日本| 欧美激情精品久久久久久| 久久亚洲国产精品五月天婷| 久久强奷乱码老熟女| 久久青青草原精品国产软件 | 波多野结衣久久精品|