通过选择等待数据不起作用
我目前正在开发一个项目,该项目涉及多个客户端连接到服务器并等待数据。我正在使用选择并监视传入数据的连接。然而,客户端只是继续不打印任何内容,就好像 select 已发现传入数据一样。也许我的攻击是错误的?
对于服务器发送的第一条数据,它会正确显示。然而,服务器随后断开连接,并且客户端继续输出空行。
FD_ZERO(&readnet);
FD_SET(sockfd, &readnet);
while(1){
rv = select(socketdescrip, &readnet, NULL, NULL, &timeout);
if (rv == -1) {
perror("select"); // error occurred in select()
} else if (rv == 0) {
printf("Connection timeout! No data after 10 seconds.\n");
} else {
// one or both of the descriptors have data
if (FD_ISSET(sockfd, &readnet)) {
numbytes = recv(sockfd, buf, sizeof buf, 0);
printf("Data Received\n");
buf[numbytes] = '\0';
printf("client: received '%s'\n",buf);
sleep(10);
}
}
}
I'm currently working on a project which involves multiple clients connected to a server and waiting for data. I'm using select and monitoring the connection for incoming data. However, the client just continues to print nothing, acting as if select has discovered incoming data. Perhaps I'm attacking this wrong?
For the first piece of data the server does send, it is displayed correctly. However, the server then disconnects and the client continues to spew blank lines.
FD_ZERO(&readnet);
FD_SET(sockfd, &readnet);
while(1){
rv = select(socketdescrip, &readnet, NULL, NULL, &timeout);
if (rv == -1) {
perror("select"); // error occurred in select()
} else if (rv == 0) {
printf("Connection timeout! No data after 10 seconds.\n");
} else {
// one or both of the descriptors have data
if (FD_ISSET(sockfd, &readnet)) {
numbytes = recv(sockfd, buf, sizeof buf, 0);
printf("Data Received\n");
buf[numbytes] = '\0';
printf("client: received '%s'\n",buf);
sleep(10);
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
当谈论你的代码时这是真的吗?
在您的简单示例中(如 qrdl 所说,FD_ZERO 和 FD_SET 移动到 while(1) 循环内),它应该如下所示:
另外 - 请注意,当 recv 返回 0 字节读取时,这意味着连接已关闭 - 没有更多数据!你的代码也有错误——当recv上发生一些不好的事情时(发生这种情况时它返回<0),你将遇到严重的麻烦,因为像buf[-1]这样的东西可能会导致不可预测的结果。请妥善处理此案。
虽然我尊重您尝试使用低级 BSD 套接字 API 的事实,但我必须说我发现它的效率非常低。这就是为什么我建议您如果可能的话使用 ACE 这是一个非常好的高效且富有成效的框架,在网络编程方面已经实现了很多功能(例如 ACE_Reactor 可以让您更轻松地完成您想要实现的目标)。
Is this true when talking about your code?
In your simple example (with FD_ZERO and FD_SET moved inside the while(1) loop as qrdl said) it should look like this:
Also - please note that when recv returns 0 bytes read it means that connection was closed - no more data! Your code is also buggy - when something bad happens on recv (it returns <0 when this happens) you will have serious trouble because something like buf[-1] may lead to unpredictable results. Please handle this case properly.
While I respect the fact that you try to use the low-level BSD sockets API I must say that I find it awfully inefficient. That's why I recommend to you if possible to use ACE which is a very efficient and productive framework which has a lot of things already implemented when it comes to network programming (ACE_Reactor for example is something that makes it easier to do what you're trying to achieve here).
我认为您需要检查
recv
的结果。如果它返回零,我相信这意味着服务器已关闭套接字。另外(取决于实现),您可能需要将
socketdescrip+1
传递给select
。I think you need to check the result of
recv
. If it returns zero, I believe it means the server has closed the socket.Also (depending on the implementation), you may need to pass
socketdescrip+1
toselect
.如果我没记错的话,您需要在每次调用
select()
之前初始化一组fd
,因为select()
会损坏它。因此,将
FD_ZERO()
和FD_SET()
移到循环内,就在select()
之前。If I remember correctly, you need to initialise set of
fd
s before each call toselect()
becauseselect()
corrupts it.So move
FD_ZERO()
andFD_SET()
inside the loop, just beforeselect()
.除了前面所说的之外,我想指出的是, select()/poll() 确实告诉您不是“数据在那里”,而是下一个相应的系统调用不会阻塞。就是这样。如上所述,recv() 不会阻塞并正确返回 0,这意味着 EOF,连接已被另一端关闭。
虽然在大多数 *nix 系统上,只有第一次调用 recv() 会返回 0,但后续调用将返回 -1。使用异步 I/O 时,必须进行严格的错误检查!
我个人强烈建议使用 poll() 代替。与 select() 不同,它不会破坏其参数,并且可以与高编号套接字描述符配合使用。
In addition to what was said before, I'd like to note that select()/poll() do tell you not when "data are there" but rather that next corresponding system call will not block. That's it. As was said above, recv() doesn't block and properly returns 0, what means EOF, connection was closed by the other side.
Though on most *nix systems in the case only first call of recv() would return 0, following calls would return -1. When using async I/O rigorous error checking is a must!
And personally I would strongly suggest to use poll() instead. Unlike select(), it doesn't destroy its arguments and works fine with high numbered socket descriptors.
当服务器关闭连接时,它会向客户端发送带有FIN标志的数据包,宣布不再发送数据。该数据包由客户端的 TCP/IP 堆栈处理,没有应用程序级别的数据。由于监控的文件描述符发生了一些事情,通知应用程序层触发 select,并且由于服务器没有发送数据,recv() 返回 0 字节。
When server closes the connection, it will send a packet taking FIN flag to client side to announce that it no longer sends data. The packet is processed by TCP/IP stack at the client side and has no data for application level. The application level is notified to trigger select because something happened on the monitored file descriptor, and recv() return 0 bytes because no data sent by server.