1

我有一个客户端和服务器,客户端运行一个select循环以在 TCP 和 UDP 连接之间进行多路复用。我正在尝试将我的 TCP 连接文件描述符添加到setreadwriteset,然后使用 set 启动一个消息交换write,一个使用readset 启动一个消息交换。我与集合的消息通信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
4

1 回答 1

5

您需要在每次调用之前初始化循环中的集合select。这是必需的,因为select修改了它们。Beej 的网络编程指南有一个全面的示例,介绍了一种使用select.

所以在你的代码中,它似乎select首先返回允许写入,但不读取,它的读取位重置为 0,然后没有什么可以将它设置回 1,因为从那时起select不会触摸它,因为它已经0。

如果selectAPI 困扰您,请查看poll,它可以避免这种情况(请注意,可能没有实际/效率差异,它基本上归结为个人喜好)。在具有许多描述符的“真实”代码(例如具有许多客户端的网络服务器)上,性能很重要,您应该使用其他一些机制,可能是一些更高级别的事件库,然后使用操作系统特定的系统 API,例如Linux 的epoll工具。但是只检查几个描述符,select是经过验证的、真实的和相对便携的选择。

于 2013-11-03T07:00:47.923 回答