我有一个服务器,该服务器具有与对应的客户端连接的多个套接字,我想使用select()来检测客户端是否正在向对应的套接字发送数据。我的代码是:
fd_set player_fd_set;
FD_ZERO(&player_fd_set);
int max_fd = players[0].connected_socket_on_master;
for (int i = 0; i < num_players; i++) {
FD_SET(players[i].connected_socket_on_master, &player_fd_set);
if (players[i].connected_socket_on_master > max_fd) {
max_fd = players[i].connected_socket_on_master;
}
}
select(max_fd + 1, &player_fd_set, NULL, NULL, NULL);
for (int i = 0; i < num_players; i++) {
printf("Check fd # %d\n", i);
if (FD_ISSET(players[i].connected_socket_on_master, &player_fd_set)) {
printf("Coming from player # %d\n", i);
ssize_t recvStatus = recv(players[i].connected_socket_on_master,
potato.trace, sizeof(potato.trace), 0);
if (recvStatus == -1) {
printf("Error: Could not recv final potato from player # %d\n", i);
exit(EXIT_FAILURE);
}
break;
}
}
似乎FD_ISSET()首次进入for循环后立即返回。我从stackoverflow中的另一个问题中了解到,select()是级别触发的,而不是边缘触发的,那么如何检测从套接字接收的数据?
谢谢!
答案 0 :(得分:1)
您的fd_set
设置很好,但是在进入阅读循环之前,您没有检查select()
的{{1}}的返回值。
您的阅读循环在错误的位置调用了> 0
,实际上它根本不应该在调用break
。一旦任何客户端发送数据,您将退出循环,而忽略其他可能也发送了等待读取数据的客户端。您需要遍历每个处于可读状态的套接字的整个break
读数。
如果fd_set
失败,则您的阅读循环不应调用exit()
。只需recv()
发生故障的套接字,将其从close()
中删除,然后继续进行下一个循环迭代即可。
如果players[]
返回-1,请确保检查recv()
中的errno
和EWOULDBLOCK
,因为它们不是致命错误。另外,如果EAGAIN
返回0,则表明客户端已断开连接。
尝试更多类似的方法:
recv()