我有一个客户端和服务器,客户端运行select
循环以在TCP和UDP连接之间进行多路复用。我正在尝试将我的TCP连接文件描述符添加到read
和write
集,然后使用write
集和使用read
集启动一个消息交换。我与write
集的消息通信工作正常,但read
设置我无法这样做。
客户代码:
char buf[256] = {};
char buf_to_send[256] = {};
int nfds, sd, r;
fd_set rd, wr;
int connect_init = 1;
/* I do the Connect Command here */
FD_ZERO(&rd);
FD_ZERO(&wr);
FD_SET(sd, &rd);
FD_SET(sd, &wr);
nfds = sd;
for(; ;){
r = select(nfds + 1, &rd, &wr, NULL, NULL);
if(connect_init == 0){
if(FD_ISSET(sd, &rd)){ // this is not working, if I change rd to wr, it works!
r = recv(sd, buf, sizeof(buf),0);
printf("received buf = %s", buf);
sprintf(buf, "%s", "client_reply\n");
send(sd, buf, strlen(buf), 0);
}
}
/* Everything below this works correctly */
if (connect_init){
if(FD_ISSET(sd, &wr)){
sprintf(buf_to_send, "%s", "Client connect request");
write(sd, buf_to_send, strlen(buf_to_send));
recv(sd, buf, sizeof(buf), 0);
printf("Server said = %s", buf);
sprintf(buf_to_send, "Hello!\n"); // client Hellos back
send(sd, buf_to_send, strlen(buf_to_send), 0);
}
connect_init = 0;
}
} // for loops ends
每次调用select
之前,都需要在循环中初始化集合。这是必要的,因为select
修改它们。 Beej's Guide to Network Programming has a comprehensive example在一种方式使用select
。
所以在你的代码中,似乎select
首先返回,允许写入,但读取没有,读取位重置为0,然后没有什么可以将它设置回1,因为从那时起select
将不会触及它,因为它已经是0了。
如果select
API困扰你,看看poll
,它避免了这一点(注意,可能没有实际/效率差异,它基本上归结为个人偏好)。在具有许多描述符的“真实”代码(例如具有许多客户端的网络服务器)上,性能很重要,您应该使用其他一些机制,可能是某些更高级别的事件库,然后使用特定于操作系统的系统API,例如Linux的epoll facility。但只检查几个描述符,select
是经过验证的真实且相对便携的选择。