0

I'm experiencing some issues with rewriting my blocking socket server to a non-blocking version. Actually, I can't seem to even get socket connected anymore, I've been googling for the most of today, and trying different solutions I find here and there, but none of them seem to work properly... Currently my server loop just keeps timeouting the select() call, with no new sockets accepted. Client socket seems to connect on some level, since if I start it, it will block trying to write, and if I close the server, it will inform that connection was reset by peer.

Is the following a correct assumption? With non-blocking server I should normally open the socket, then set it's flags to non-blocking, bind it, and the start calling select for read file descriptor and wait for it to populate ? I need to remove old blocking "accept()" call, which was waiting endlessly.. If I try calling accept, it will -1 on me now...

Here is the relevant code I'm trying now

fd_set incoming_sockets;
....
int listener_socket, newsockfd, portno;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
....
listener_socket = socket(AF_INET, SOCK_STREAM, 0); //get socket handle
int flags = fcntl(listener_socket, F_GETFL, 0);
if( fcntl(listener_socket, F_SETFL, flags | O_NONBLOCK) < 0 )
    log_writer->write_to_error_log("Error setting listening socket to non blocking", false);
memset(&serv_addr, 0, sizeof(struct sockaddr_in));

serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
....
if (bind(listener_socket, (struct sockaddr *) &serv_addr,
        sizeof(struct sockaddr_in)) < 0)
{
    log_writer->write_to_error_log("Unable to bind socket, aborting!", true);
}
....
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;

int ready_sockets = 0;

listen(listener_socket,1);

FD_ZERO(&incoming_sockets); 
FD_SET(listener_socket, &incoming_sockets); 

while(true)
{

ready_sockets = select(listener_socket + 1 , &incoming_sockets, (fd_set * ) 0, (fd_set * ) 0, &timeout  );

if(ready_sockets == 0)
    {
        //I loop here now for ever
        std::cout << "no new sockets available, snooze 2\n";
        sleep(2);
    } else
    {
    std::cout << "connection received!\n";
tshepang
  • 12,111
  • 21
  • 91
  • 136
julumme
  • 2,326
  • 2
  • 25
  • 38
  • You should really check the return value of `select` for errors. Might not be a problem in your case right now, but might be in the future. Other than that I can't see any obvious error in your code. – Some programmer dude Jan 17 '12 at 09:23
  • Hi Joachim, thanks for your reply! Actually I do check for other values as well (if < 0), but since I keep going to == 0 now, I decided to omit it for readability... – julumme Jan 17 '12 at 09:28

2 Answers2

1

Since you don't show the whole loop, I don't know if you do it later, but you should initialize the descriptor sets and timeout structure before every call to select.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Ah! This seemed to do the trick!Indeed I initialized the file descriptors only outside the while loop, now I was able to get the client connected – julumme Jan 17 '12 at 09:45
0

You should mover the fd_zero() fd_set() macros inside the loop, select will actually change the bitmasks in the fd_sets (and the timeout value). Reinitialise them on every iteration. Also check for select returning -1 and the associated errno (EPIPE ...)

while(true)
{

FD_ZERO(&incoming_sockets); 
FD_SET(listener_socket, &incoming_sockets); 



ready_sockets = select(listener_socket + 1 , &incoming_sockets, (fd_set * ) 0, (fd_set * ) 0, &timeout  );

if(ready_sockets == 0)
    {
      ... }
wildplasser
  • 43,142
  • 8
  • 66
  • 109
  • Thank you wildplasser for your comment, this was indeed the correct solution, same as Joachim noticed! – julumme Jan 17 '12 at 21:46