为什么读取套接字的内容需要很长时间才能完成

问题描述 投票:0回答:1

背景

我目前正在 Linux 中制作一个使用 SSL 安全 IPv4 套接字的程序。创建套接字后,它们会连接到 IP 并发出请求

socket->Connect( ip.c_str() , port );
socket->Write(  request.c_str(), strlen(request.c_str()) );

之后,我使用缓冲区循环读取页面的内容,然后将缓冲区的内容累积在字符串中。缓冲区还会在每次迭代中进行清理,以避免覆盖内容。

int bytes_read = 0;
char buffer[buffer_size]; // where buffer_size is an arbitrary number 512 for example
do {
    socket->Read(buffer, buffer_size);
    bytes_read = socket->Read(buffer, buffer_size);
    result += buffer;
    // std::cout << buffer << std::endl;
    memset(buffer, 0, buffer_size);
} while (bytes_read > 0);

代码非常简单,正如我所说,我使用带有 SSL 连接的套接字,但我没有在套接字上使用任何额外的标志。但是,一旦程序运行,即使连接到非常简单的页面,也需要相当长的时间才能完成。

因此,我决定在每次迭代中输入缓冲区的内容,我注意到程序几乎立即读取内容,但程序在完成执行之前又运行了 5 秒钟。在像维基百科这样的较大页面中,它不会完成,因为我必须执行 Ctrl^z。

因此我的问题是,为什么会发生这种情况?我不明白这种行为,read的手册页如下:

       On success, the number of bytes read is returned (zero indicates
       end of file), and the file position is advanced by this number.
       It is not an error if this number is smaller than the number of
       bytes requested; this may happen for example because fewer bytes
       are actually available right now (maybe because we were close to
       end-of-file, or because we are reading from a pipe, or from a
       terminal), or because read() was interrupted by a signal

据我了解,一旦到达 EOF,它将返回 0,然后它应该退出循环。

预期的行为当然是在读取内容后退出循环。事实上,如果我只读取一次而不是循环读取,程序就会在 < 1 seconds. This is however something I don't want to implement as the function read can fail and not read all the bytes specified in size and I need to ensure that all the contents of the page are read.

中完成

我尝试过的事情

到目前为止,我已经尝试在套接字中使用超时

struct timeval timeout;
timeout.tv_sec = 10; // 10 secs
timeout.tv_usec = 0;

if (setsockopt(socket->getDescriptor(), SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) {
    perror("setsockopt failed");

以及使其成为非阻塞

int flags = fcntl(sockfd, F_GETFL, 0);

但是并没有奏效。我想了解为什么会发生这种情况,以及如何确保读取页面的所有内容,而不会出现程序无法结束或花费大量时间的问题。我很感谢您的帮助,谢谢。

c++ sockets unix
1个回答
0
投票

你没有直接说出来,但你似乎在谈论 HTTP(特别是 HTTP/1.1),所以我将继续这个假设。

您正在等待连接关闭,但发送响应后连接并未关闭(通常不应该关闭)。但最终,服务器厌倦了等待您发送其他内容,并关闭连接。需要多长时间取决于服务器。

读取 HTTP 响应的正确方法是真正理解 HTTP 协议:读取并解析标头,然后读取

Content-Length
字节的正文(如果已设置),或者 读取块 直到达到 0 长度的块(如果)
Transfer-Encoding
包含
chunked

如果您无法做到这一点,您可以发送标头

Connection: close
来指示您不会再在连接上发送任何请求,并且服务器应在发送响应后关闭连接,但这是一个做任何事情都是低效的。

© www.soinside.com 2019 - 2024. All rights reserved.