SslStream.Read()的奇怪行为

时间:2012-08-28 14:39:16

标签: c# .net c#-4.0 .net-4.0 sslstream

使用SslStream处理某些套接字层。的 reference

使用该引用,我实现了一个简单的客户端。尴尬的部分是当你运行应用程序时,似乎服务器没有回复客户端。

进入调试屏幕并设置一些断点,我意识到这个函数是无限循环的。

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会显示响应已写入buffercrlf。这个功能完成了它的工作,但它还没有成功回归?!

这可能是什么原因?我应该采取哪些步骤来忽略这个问题?

此外,对于怀疑者:我使用openssl来查看服务器是否正常运行,服务器端的一切正常。

注意:我已经知道SslStream.ReadTimeout属性了。虽然它通过引发exception来完成这项工作,但它并不是每个场景的正确答案,特别是当服务器响应大量数据时,只能使用while循环和缓冲区有效读取。

3 个答案:

答案 0 :(得分:2)

我和我一样苦苦挣扎,程序无限循环。

我通过以下信息解决了

如果您使用http,https协议?你添加到标题,“连接:关闭\ r \ n”

Http Standart Article

14.10连接

Connection general-header字段允许发送方指定该特定连接所需的选项,并且代理不得通过其他连接进行通信。

Connection标头具有以下语法:

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

HTTP / 1.1代理必须在转发消息之前解析Connection头字段,并且对于此字段中的每个连接令牌,从消息中删除任何与connection-token同名的头字段。连接选项通过Connection头字段中存在连接令牌而不是任何相应的附加头字段来表示,因为如果没有与该连接选项关联的参数,则可能不会发送附加头字段。 / p>

Connection头中列出的消息头不得包含端到端头,例如Cache-Control。

HTTP / 1.1定义了“close”连接选项,发送方在完成响应后发出连接将被关闭的信号。例如,

   **Connection: close**
请求或响应头字段中的

表示在当前请求/响应完成后,连接不应被视为“持久”(第8.1节)。

不支持持久连接的HTTP / 1.1应用程序必须在每条消息中包含“关闭”连接选项。

接收包含Connection头的HTTP / 1.0(或更低版本)消息的系统必须为此字段中的每个连接令牌删除并忽略来自消息的任何头字段,其名称与连接令牌。这可防止前HTTP / 1.1代理错误地转发此类头字段。见第19.6.2节。

答案 1 :(得分:1)

如果连接仍处于打开状态且服务器尚未写入<EOF>,那么它只是“悬挂”是绝对有意义的。它在等待更多数据。它可以知道没有更多数据的唯一方法是服务器关闭连接。

它是否已设法读取服务器实际发送的所有数据?在未返回的调用之前,messageData在迭代上的样子是什么?

答案 2 :(得分:-2)

经过一番思考后,我想出了一个解决方法。

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

不得不使用超时,似乎没有其他工作。修改了Reader来处理异常。

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();
}

虽然这有效,但并不意味着它是一个很好的答案。如果有人能提供更好的答案,那就太好了。