3

使用 SslStream 处理一些套接字层。参考

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

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

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[] bufferin debug 屏幕显示响应已写入到buffertill crlf。该功能已经完成了它的工作,但它仍然没有成功返回?!

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

另外,对于持怀疑态度的人:我曾经openssl查看服务器是否正常运行,并且服务器端的一切都很好。

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

4

3 回答 3

2

我一直在为同样的问题而苦苦挣扎,程序是无限循环的。

我通过以下信息解决了

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

Http 标准文章

14.10 连接

Connection general-header 字段允许发送者指定该特定连接所需的选项,并且不能由代理通过进一步的连接进行通信。

Connection 标头具有以下语法:

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

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

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

HTTP/1.1 为发送者定义了“关闭”连接选项,以表明在响应完成后连接将被关闭。例如,

   **Connection: close**

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

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

接收包含 Connection 标头的 HTTP/1.0(或更低版本)消息的系统必须,对于此字段中的每个连接令牌,从消息中删除并忽略与连接同名的任何标头字段 -令牌。这可以防止 HTTP/1.1 之前的代理错误地转发此类标头字段。请参阅第 19.6.2 节。

于 2015-02-01T00:35:05.827 回答
1

如果连接仍然打开并且服务器尚未写入<EOF>,那么它只是“挂起”绝对是有道理的。它正在等待更多数据。它可以知道没有更多数据的唯一方法是让服务器关闭连接。

它是否已经设法读取了服务器实际发送的所有数据?在没有返回的调用之前messageData的迭代中看起来像什么?

于 2012-08-28T14:43:20.147 回答
-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();
}

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

于 2012-08-29T16:20:30.167 回答