在侦听套接字上使用select()

时间:2017-03-03 12:10:36

标签: c linux sockets select bind

我想打开一个端口并等待传入​​的连接,但是我无法让select()工作。我让它与poll()一起使用,但我需要select()才能实现可移植性。我做错了什么?

等待连接的代码如下所示(我需要每隔200ms检查一次中断):

/* Wait for a descriptor */
int wait_for_fd(int fd){
  int waitms = 200;
  struct timeval tv;
  tv.tv_sec = 0;
  tv.tv_usec = waitms * 1000;
  fd_set rfds;
  FD_ZERO(&rfds);
  FD_SET(fd, &rfds);
  int active = 0;
  while(active == 0){
    active = select(fd+1, &rfds, NULL, NULL, &tv);
    bail_for(active < 0, "select()");
    if(pending_interrupt())
      break;
  }
  return active;
}

然后我的代码实际打开一个端口并等待连接:

int open_port(int port){

  // define server socket
  struct sockaddr_in serv_addr;
  memset(&serv_addr, '0', sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  serv_addr.sin_port = htons(port);

  //creates the listening socket
  int listenfd = socket(AF_INET, SOCK_STREAM, 0);
  bail_for(listenfd < 0, "socket()");
  bail_for(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0, "bind()");
  bail_for(listen(listenfd, 10) < 0, "listen()");

  //each accept() is a new incoming connection
  printf("Waiting for connetion on port %d...\n", port);
  wait_for_fd(listenfd);
  int connfd = accept(listenfd, NULL, NULL);
  bail_for(connfd < 0, "accept()");
  printf("Incoming connection!\n");

  //do not allow additional client connetions
  close(listenfd);
  return connfd;
} 

但是,即使客户端正在连接,wait_for_fd()也永远不会返回(由于select始终返回0)。

2 个答案:

答案 0 :(得分:4)

必须在每次迭代时都这样:

FD_ZERO(&rfds);
FD_SET(fd, &rfds);

因为rfdsselect()的输入/输出参数。它实际上告诉它哪些fds受到了影响。

答案 1 :(得分:2)

根据select

的联系方式
  

退出时,会对这些集进行修改,以指示哪些文件描述符实际更改了状态。如果没有为相应的事件类观察文件描述符,则可以将三个文件描述符集中的每一个指定为NULL。

这意味着,当您调用select并且没有更改文件描述符时,rfds中没有设置文件描述符。因此,您必须在每次迭代时设置它们

while(active == 0){
    FD_ZERO(&rfds);
    FD_SET(fd, &rfds);
    active = select(fd+1, &rfds, NULL, NULL, &tv);
    bail_for(active < 0, "select()");
    if(pending_interrupt())
      break;
  }