【问题标题】:How to determine when data is finished on an SSL socket如何确定 SSL 套接字上的数据何时完成
【发布时间】:2014-01-30 08:47:53
【问题描述】:

我正在编写一个应用程序,它创建多个到 https 服务器的非阻塞 SSL 连接,在每个连接中我发送一个请求并读取服务器的响应。我的问题是,无论我做什么,我都无法确定响应数据何时完成。这是我负责发送和接收数据的代码的一部分:

....
fd_set connectionfds;
struct timeval timeout2;
FD_ZERO(&connectionfds);
FD_SET(socket_server, &connectionfds);
timeout2.tv_usec = 0;
timeout2.tv_sec = 1;
while(1)
{
    r=BIO_read(io,buf,BUFSIZZ-1);
    if (r>0){
        //gather data
        continue;
    }
    else if (SSL_get_error(ssl, r)==SSL_ERROR_WANT_READ){
        int ret = select(socket_server + 1, &connectionfds, NULL, NULL, &timeout2);
        if (ret <= 0){
            break;
        }
        continue;
    }
    else{
        break;
    }
}
// use whole gathered data
....

我对上面代码的问题是,如果我将选择超时设置为小时间,我不能保证所有数据都被接收(因为有些服务器真的很慢),如果我设置超时时间很长(5 -10 秒),我的套接字长时间处于等待状态,在此之前我无法使用响应。 我试图通过使用“BIO_should_read()”或“BIO_pending()”函数来完成这项工作,但它们都没有给我我想要的东西。 那么,有没有办法确定什么时候 SSL 套接字上没有其他内容可以读取?

【问题讨论】:

  • “我无法确定响应数据何时完成”是什么意思?是否表示连接已关闭?
  • @MarianV 我正在编写一个类似浏览器的应用程序。当我尝试从任何 https 网站(如 yahoo-mail 等)获取响应时,在我发送我的 http 请求后,我使用 BIO_read 读取响应,但在读取整个响应后没有任何反应,我必须等待很长时间select() 超时,知道响应完成。 Firefox、chrome 等浏览器如何感知这一点?因为他们都在收到全部数据后立即关闭连接。

标签: c sockets select ssl timeout


【解决方案1】:

正如 Steffen 所说,SSL 和 TCP/IP 流中没有“数据结束”的概念。现代 http 服务器使用“保持活动”连接,并且在回答您的请求后不会断开连接。相反,他们正在使用您需要推断答案长度的附加信息。它要么是“Content-lenght”标头,要么使用“Transfer-Encoding:chunked”,后跟数据块。每个块前面都有大小(作为十六进制数)。大小为零的块意味着答案的结束。

对您而言,获得可用内容的最简单方法可能是将请求作为 HTTP 1.0 请求(而不是 HTTP 1.1)发送。如果您发出这样的请求:

GET /myrequestdir/myrequestfile HTTP/1.0

服务器将在响应您的请求后立即关闭连接。

如果您需要 HTTP 1.1,这里有两个示例,服务器如何回答“你好”。留言:

HTTP/1.1 200 OK
Content-Length:6

Hello.

或使用分块连接:

HTTP/1.1 200 OK
Transfer-Encoding: chunked

6
Hello.

0

【讨论】:

  • 谢谢。我更改了代码,并使用 HTTP/1.0 而不是 1.1,这对我有很大帮助。
  • 您节省了我寻找这个完美答案的 3 个辛勤工作天。非常感谢!!
【解决方案2】:

为什么你使用 BIO_read,而不是 SSL_read?在我看来,将 SSL 层与 SSL_get_error 一起使用,然后不要将同一层与 SSL_read 一起使用,而是将底层 BIO 层与 BIO_read 一起使用,这是一个坏主意。您也不处理这种情况,其中 SSL_get_error 可能不返回错误或 SSL_ERROR_WANT_READ(在(重新)协商的情况下)。

至于您的问题,关于您如何知道数据何时完成:SSL 就像底层 TCP 一个基于流的协议,例如与 UDP 等基于数据包的协议相反,没有“数据包结束”。因此,如果 SSL 连接完成,您的数据就完成了。如果你想拥有其他东西,你必须调整你的应用程序协议,在流层之上创建一个数据包层。

或者您的意思是,您想知道当前 SSL 帧何时完成?虽然 SSL 应用作流式传输协议,但它以最大 16k 的可变大小帧发送其数据。每个 SSL_write 都会产生一个新帧(如果一次发送更多发送 16k 可能会更多),但每个 SSL_read 只会读取一个帧,例如如果它没有得到整个帧或返回帧的解密内容,它将返回一个错误(SSL_WANT_*)。这就是您知道框架已被完全读取的方式。

【讨论】:

    猜你喜欢
    • 2019-05-13
    • 2019-01-28
    • 2021-11-26
    • 2019-02-20
    • 2011-05-07
    • 2013-08-19
    • 1970-01-01
    • 2012-09-15
    • 2017-03-18
    相关资源
    最近更新 更多