【问题标题】:Using select() on listening socket在侦听套接字上使用 select()
【发布时间】:2017-07-23 13:05:00
【问题描述】:

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

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

/* 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)。

【问题讨论】:

  • select 的便携性?可移植到什么? PDP-11? select 速度非常慢,除非你做了一些非常奇怪、不可移植和未记录的黑客行为,否则当你打开超过 X(通常为 1024)个文件描述符时,你将开始崩溃和/或覆盖随机内存。 select 已经死了,如果不是 15 年前,至少应该从标准中删除 10 年。请重新考虑。在新软件中使用 select 就像在新加密中使用 MD5。
  • Windows (mingw-w64) 没有poll()
  • @Art 可移植到 POSIX。 poll 在性能方面并没有好多少,并且不支持原子解锁信号。 1024 的限制几乎不是问题,如果你有那么多文件描述符,你应该把 POSIX 放在一边,作为 O(1) 的替代方案,但如果你只有几个文件描述符,这样的替代方案就过分了。

标签: c linux sockets select bind


【解决方案1】:

根据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;
  }

【讨论】:

  • 谢谢!很有帮助!
【解决方案2】:

这必须在每次迭代中:

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

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

【讨论】:

  • 谢谢!这确实是问题所在。
猜你喜欢
  • 2011-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-19
  • 2017-09-03
  • 1970-01-01
  • 1970-01-01
  • 2018-12-23
相关资源
最近更新 更多