C:具有超时的非阻塞套接字:如何检查是否发出了连接请求?

时间:2015-02-27 11:49:05

标签: c sockets timeout blocking

我希望有一台服务器一次连接到一个客户端,在连接到给定客户端时忽略连接请求。

我还希望避免服务器在收听第一个客户端时被锁定,以便程序可以干净地终止。

显然,套接字可以是非阻塞的: http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#blocking

我相应地创建了我的套接字(为清楚起见,删除了错误管理代码)

int sockfd;
struct sockaddr_in self;
sockfd = socket(AF_INET, SOCK_STREAM, 0));
fcntl(sockfd, F_SETFL, O_NONBLOCK); // making this socket non blocking
bzero(&self, sizeof(self));
self.sin_family = AF_INET;
self.sin_port = htons(port);
self.sin_addr.s_addr = inet_addr("127.0.0.1");   // allowing connection from localhost only.                                            
bind(sockfd, (struct sockaddr*)&self, sizeof(self));

从那时起,我不确定如何管理超时。以下代码不起作用,但提供了我想要实现的目标。

int client_found = 0;
while ( no_stop_signal && client_found==0 ) {
    listen(sockfd,1);
    if ( ** something that tells me nobody was requesting connection ** ) {
       usleep(10);
   } else {
       client_found = 1;
   }
}

到目前为止,我发现的任何解决方案都关注的情况比我的情况更复杂(即一旦找到客户就不会忽视客户)并且似乎不必要地复杂化。

编辑(接受答案后):

根据接受的答案,这里是我附带的代码:

static inline int wait_for_client_to_connect(int sockfd, int* server_run){                                                                                                                                                                                  
  int client_found = 0;                                                                                                                                                                                                                                        
  int clientfd = 0;                                                                                                                                                                                                                                            
  struct sockaddr_in client_addr;                                                                                                                                                                                                                              
  int addrlen=sizeof(client_addr);                                                                                                                                                                                                                             
  if ( listen(sockfd,1) != 0 ) return -1;                                                                                                                                                                                                                      
  while ( client_found==0 && *server_run==1 ) {                                                                                                                                                                                                                 
    clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen);                                                                                                                                                                                       
    if ( clientfd < 0 ) {                                                                                                                                                                                                                                      
      clientfd = 0;                                                                                                                                                                                                                                            
      if (errno==EAGAIN || errno==EWOULDBLOCK) usleep(10); // nobody connected, wait for request                                                                                                                                                               
      else return -1; // something wrong, send error                                                                                                                                                                                                           
    } else { // client found, configuring socket and exit                                                                                                                                                                                                      
      client_found=1;                                                                                                                                                                                                                                          
      int nodelay_flag = 1;                                                                                                                                                                                                                                    
      setsockopt(clientfd, IPPROTO_TCP, TCP_NODELAY, (void*) &nodelay_flag, sizeof(int)); // disable nagle algorithm                                                                                                                                           
    }                                                                                                                                                                                                                                                          
  }                                                                                                                                                                                                                                                            
  return clientfd;                                                                                                                                                                                                                                             
}                                                                                                                                                                                                                                                              

这有效,但根据评论和回答,这不是要走的路(显然干净的方式与信号有关......)

1 个答案:

答案 0 :(得分:2)

只需在侦听(非阻塞)套接字上调用accept()即可。

如果积压中没有等待连接,则accept()将立即返回-1errno将设置为EGAINEWOULDBLOCK

来自man accept

  

<强>错误

     

EAGAIN或EWOULDBLOCK

     

套接字标记为非阻塞,并且不存在要接受的连接。 POSIX.1-2001允许在这种情况下返回错误,并且不要求这些常量具有相同的值,因此便携式应用程序应检查这两种可能性。


然而,你所展示的while - 循环会实现忙等待,这非常昂贵。

那么为什么不让accept通过简单地阻塞来等待直到检测到传入连接。

要阻止阻止accept(),只需向进程发送信号即可。 accept()然后返回时-1errno设置为EINTR


  

我想有一台连接到一个客户端的服务器

根据定义,它始终是连接到服务器的客户端。