使用select和recv通过套接字从Web服务器获取文件

我在使用C套接字从Web服务器接收“大”文件时遇到问题; 即当这些文件(或我怀疑)大于我用来接收它们的缓冲区的大小时。 如果我试图(通过GET请求)询问一个不大于几个字节的简单index.html ,我会很好,但其他任何事情都会失败。 我假设我对select()recv()缺乏了解,这让我失望了。 看这里:

 fd_set read_fd_set; FD_ZERO(&read_fd_set); FD_SET((unsigned int)socketId, &read_fd_set); /* Initialize the timeout data structure. */ struct timeval timeout; timeout.tv_sec = 2; timeout.tv_usec = 0; // Receives reply from the server int headerReceived = 0; do { select(socketId+1, &read_fd_set, NULL, NULL, &timeout); if (!(FD_ISSET(socketId, &read_fd_set))) { break; } byteSize = recv(socketId, buffer, sizeof buffer, 0); if (byteSize == 0 || (byteSize < BUFFER_SIZE && headerReceived)) { break; } headerReceived = 1; } while(1); 

这是正确的,在将GET请求发送到Web服务器之后,我非常确定服务器正常,并且来自任何其他客户端(如任何Web浏览器)的GET请求正在按预期工作。

在此先感谢,非常感谢任何帮助。

我发现的一件事是你不会在循环过程中重新初始化选择。 这可能是您成功获得小文件的原因; 它们一次接收,循环不必迭代。

我建议你把:

 FD_ZERO(&read_fd_set); FD_SET((unsigned int)socketId, &read_fd_set); timeout.tv_sec = 2; timeout.tv_usec = 0; 

在循环内部(在调用select之前),它可能正常工作。

 if (byteSize == 0 || (byteSize < BUFFER_SIZE && headerReceived)) { break; } 

第一次读取后headerReceived设置为true。 它完全有可能,后续的recv() 可能会小于BUFFER_SIZE 。 那时你已经不在读循环中了。 Recv()将返回要读取的字节数,不一定是您请求的字节数。

也可以坚持使用BUFFER_SIZEsizeof(buffer) 。 混合和匹配只是要求在路上的某个地方出现错误。

您没有说出您正在使用的O / S,但根据POSIX规范 :

成功完成后, select ()函数可以修改timeout参数指向的对象。

(我相信Linux就是这样做的。)

因此,循环的后续调用很可能将超时设置为零,这将导致select立即返回而没有准备好描述符。

我建议在每次循环调用select之前立即重新初始化超时结构。