C : non blocking sockets with timeout : how to check if connection request was made?

流过昼夜 提交于 2020-02-05 10:00:30

问题


I would like to have a server that connects to one client at a time, ignoring connection request when connected to a given client.

I would also liked to avoid the server to get locked when listening for the first client, so that the program can be terminated cleanly.

Apparently, sockets can be made non blocking: http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#blocking

I created my socket accordingly (error management code removed for clarity)

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));

From that point, I am not sure how to manage a timeout. The following code does not work, but gives an idea what I would like to achieve.

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

Any solution I found so far were concerned about situation more complex than mine (i.e. not ignoring clients once one had been found) and seemed unnecessarily complicated.

EDIT (after accepting answer):

Based on the accepted answer, here the code I came with:

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

This works, but according to comments and answer, this is not the way to go (apparently a clean way would have something to do with signals ...)


回答1:


Just call accept() on the listening (non-blocking) socket.

If no connection was waiting in the backlog then accept() would return immediately with -1 and errno would be set to EGAIN or EWOULDBLOCK.

From man accept:

ERRORS

EAGAIN or EWOULDBLOCK

The socket is marked nonblocking and no connections are present to be accepted. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.


However the while-loop your are showing would implement busy-waiting, which is quite expensive.

So why not let accept do the waiting by simply blocking until an incoming connection is detected.

To interupt the blocking accept() just send the process a signal. accept() then would return with -1 and errno being set to EINTR.


I would like to have a server that connects to one client

By definitions it's always the client which connects to the server.



来源:https://stackoverflow.com/questions/28764440/c-non-blocking-sockets-with-timeout-how-to-check-if-connection-request-was-m

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!