使用select和recv通过套接字从web服务器获取文件
使用C套接字从web服务器接收大文件时遇到问题;也就是说,我怀疑这些文件大于我用来接收它们的缓冲区的大小。如果我试图通过GET请求请求一个不超过几个字节的简单index.html,我会得到很好的结果,但其他任何操作都会失败。我认为我缺乏select或recv方面的知识是我失败的原因。请看这里:使用select和recv通过套接字从web服务器获取文件,c,sockets,C,Sockets,使用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); /* I
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浏览器)获取请求都能正常工作
提前感谢,我们非常感谢您的帮助。您没有说明您使用的是什么O/S,但根据: 成功完成后,选择功能可以修改 超时参数指向的对象 我相信Linux就是这样做的 因此,很有可能稍后对循环的调用将超时设置为零,这将导致select在没有准备好描述符的情况下立即返回
我建议在每次通过循环调用select之前立即重新初始化超时结构。您没有说明您正在使用什么O/S,但根据:
if (byteSize == 0 || (byteSize < BUFFER_SIZE && headerReceived))
{
break;
}
成功完成后,选择功能可以修改
超时参数指向的对象
我相信Linux就是这样做的
因此,很有可能稍后对循环的调用将超时设置为零,这将导致select在没有准备好描述符的情况下立即返回
我建议在每次通过循环调用select之前立即重新初始化超时结构
if (byteSize == 0 || (byteSize < BUFFER_SIZE && headerReceived))
{
break;
}
首次读取后,headerReceived设置为true。这是完全可能的,并且后续RECV可能会小于缓冲区大小。此时,您已脱离读取循环。Recv将返回要读取的字节数,而不一定返回您请求的字节数
也可以使用缓冲区大小或sizeofbuffer。混合和匹配只是在路上的某个地方寻找一个bug
首次读取后,headerReceived设置为true。这是完全可能的,并且后续RECV可能会小于缓冲区大小。此时,您已脱离读取循环。Recv将返回要读取的字节数,而不一定返回您请求的字节数
也可以使用缓冲区大小或sizeofbuffer。混合和匹配只是在路上的某个地方询问一个bug。我发现的一件事是,在循环过程中不重新初始化选择。这可能就是您成功获取小文件的原因;它们是一次性接收的,循环不必迭代 我建议您将以下内容:
FD_ZERO(&read_fd_set);
FD_SET((unsigned int)socketId, &read_fd_set);
timeout.tv_sec = 2;
timeout.tv_usec = 0;
在调用select之前,它可能会在循环内部工作。我发现的一件事是,在循环期间,您不会重新初始化选择。这可能就是您成功获取小文件的原因;它们是一次性接收的,循环不必迭代 我建议您将以下内容:
FD_ZERO(&read_fd_set);
FD_SET((unsigned int)socketId, &read_fd_set);
timeout.tv_sec = 2;
timeout.tv_usec = 0;
在调用select之前在循环内部,它可能会正常工作。它是Linux。谢谢你的建议,但不幸的是,这似乎并没有解决它。它是Linux。谢谢你的建议,但不幸的是,这似乎并没有解决它。好吧,这似乎是结合了这一点和鸭子的答案做的把戏,谢谢!好吧,看来这和Duck的回答结合在一起成功了,谢谢!这似乎改善了行为,谢谢!这和EitanT的改变相结合似乎起到了作用:这似乎改善了行为,谢谢!结合这一点和EitanT的改变似乎已经达到了目的:我认为假设byteSize