2012-08-28 50 views
2

使用SslStream處理一些套接字層。 referenceSslStream.Read()的奇怪行爲

使用該參考,我實現了一個簡單的客戶端。尷尬的部分是當你運行應用程序,似乎服務器沒有回覆客戶端。

進入調試屏幕並設置一些斷點,我意識到這是一個無限循環的功能。

static string ReadMessage(SslStream sslStream) 
{ 
    // Read the message sent by the server. 
    // The end of the message is signaled using the 
    // "<EOF>" marker. 
    byte [] buffer = new byte[2048]; 
    StringBuilder messageData = new StringBuilder(); 
    int bytes = -1; 
    do 
    { 
     bytes = sslStream.Read(buffer, 0, buffer.Length); 

     // Use Decoder class to convert from bytes to UTF8 
     // in case a character spans two buffers. 
     Decoder decoder = Encoding.UTF8.GetDecoder(); 
     char[] chars = new char[decoder.GetCharCount(buffer,0,bytes)]; 
     decoder.GetChars(buffer, 0, bytes, chars,0); 
     messageData.Append (chars); 
     // Check for EOF. 
     if (messageData.ToString().IndexOf("<EOF>") != -1) 
     { 
      break; 
     } 
    } while (bytes != 0); 

    return messageData.ToString(); 
} 

進一步調查這裏指出,真正的罪犯:

bytes = sslStream.Read(buffer, 0, buffer.Length); 

好像,SslStream.Read()沒有返回。在調試屏幕中檢查byte[] buffer可以發現響應已被寫入buffer,直到crlf。這個功能已經完成了它的工作,但是它還沒有成功返回?!

這可能是什麼原因?我應該採取哪些措施來忽略這個問題?

此外,對於持懷疑態度的人:我以前openssl,看看服務器行爲,因爲它應該,什麼都在服務器端的罰款。

注意:我已經知道SslStream.ReadTimeout屬性。儘管它通過提高exception來完成這項工作,但對於每種情況都不是正確的答案,特別是當服務器響應大量數據流時,只能使用while循環和緩衝區高效讀取數據。

+0

您是否使用SslSocket.BeginRead/EndRead獲得任何不同的行爲? –

+0

我還沒有試過,等一下,讓我檢查一下。 @PeterRitchie –

回答

1

如果連接仍然打開並且服務器沒有寫入<EOF>那麼它絕對有意義的是它只是「掛起」。它正在等待更多數據。它可以知道沒有更多數據的唯一方法是服務器關閉連接。

它已經設法讀取服務器實際發送的所有數據嗎? messageData在之前的迭代上看起來是什麼樣子?

+0

服務器已回覆成功,以''結束響應。看一下'調試'屏幕驗證。 –

+1

是的,它設法讀取所有數據直到'crlf'。 'messageData'看起來不像什麼,因爲'.Read()'被卡住了,添加一個'timeout'顯示'messageData'包含了服務器返回的所有'response'。 –

-1

經過一番思考後,我想出了一個解決方法。

sslStream.ReadTimeout = 100; //How much time does it takes for a processor to read and write 2048bytes to the buffer? 

不得不使用超時,沒有別的似乎工作。修改閱讀器以處理異常。

static string ReadMessage(SslStream sslStream) 
{ 
    // Read the message sent by the server. 
    // The end of the message is signaled using the 
    // "<EOF>" marker. 
    byte[] buffer = new byte[2048]; 
    StringBuilder messageData = new StringBuilder(); 
    int bytes = -1; 

    do 
    { 
     try 
     { 
      bytes = sslStream.Read(buffer, 0, buffer.Length); 

     } 
     catch (Exception ex) 
     { 
     } 
     // Use Decoder class to convert from bytes to UTF8 
     // in case a character spans two buffers. 
     Decoder decoder = Encoding.ASCII.GetDecoder(); 
     char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)]; 
     decoder.GetChars(buffer, 0, bytes, chars, 0); 
     messageData.Append(chars); 
     // Check for EOF. 
     if (messageData.ToString().IndexOf("\r\n") != -1) 
     { 
      break; 
     } 

    } 
    while (bytes != -1); 



    return messageData.ToString(); 
} 

雖然這個工作,並不意味着這是一個很好的答案。如果有人能提供更好的答案,那就太好了。

1

我一直在與我一樣的問題掙扎,程序是無限循環。

我通過以下信息解決了

如果你使用http,https協議?添加到頭部,「連接:關閉\ r \ n」個

Http Standart Article

14.10連接

的連接通用頭域允許發送方指定所期望用於該特定連接,並且必須選擇不通過代理通過進一步的連接進行通信。

Connection頭具有以下語法:

Connection = "Connection" ":" 1#(connection-token) 
    connection-token = token 

HTTP/1.1代理必須分析連接頭字段被轉發之前的消息,並且對於在此字段中的每個連接標記,除去任何報頭字段( s)從與連接令牌同名的消息中刪除。連接選項通過連接標頭字段中的連接令牌而不是任何相應的附加標頭字段來標誌,因爲如果沒有與該連接選項相關的參數,則可能不會發送附加標頭字段。

連接頭中列出的消息頭必須不包含端到端頭,如Cache-Control。

HTTP/1.1爲發送者定義了「關閉」連接選項,表示連接將在完成響應後關閉。例如,

**Connection: close** 

在任一方請求或響應的報頭字段指示連接不應被視爲`持久」當前請求後(第8.1節)/響應完成。

不支持持久連接的HTTP/1.1應用程序必須在每條消息中包含「關閉」連接選項。

接收包含Connection頭的HTTP/1.0(或更低版本)消息的系統必須爲該字段中的每個連接令牌移除並忽略具有相同名稱的消息中的任何頭字段作爲連接令牌。這可以防止HTTP-1.1前置代理錯誤地轉發這些頭字段。參見第19.6.2節。