1

I have a simple socket server set up using sys/socket and OpenSSL. For each connection, the client is required to send a message to the server, receive a response and then reply to that response.

I can't find any clear mechanism for making these sockets non-blocking? The system has to be able to handle multiple sockets concurrently...

My server code for listening for connections:

while(1)
{
   struct sockaddr_in addr;
   uint len = sizeof(addr);
   SSL *ssl;            
   int client = accept(sock, (struct sockaddr*)&addr, &len);
   if (client > 0) 
   {
      std::cout<<"Client accepted..."<<std::endl;
   }
   else
   {
      perror("Unable to accept");
      exit(EXIT_FAILURE);
   }

   ssl = SSL_new(ctx); 
   SSL_set_fd(ssl, client);

   if (SSL_accept(ssl) <= 0)
   {
      std::cout<<"ERROR"<<std::endl;
   }
   else
   {
      char buff[1024];
      SSL_read(ssl, buff, 1024);
      std::cout<<buff<<std::endl;

      std::string reply="Thanks from the server";
      char buff_response[1024];
      reply.copy(buff_response, 1024);
      const void *buf=&buff_response;
      SSL_write(ssl, buf, 1024);

      char another_buff[1024];
      SSL_read(ssl,another_buff,1024);
      std::cout<<another_buff<<std::endl;
   }
}

I've looked into 'select()', however this doesn't seem to allow concurrency as such, but allows the system to know when a socket is freed?

Does anyone have any experience in solving this basic problem?

Babra Cunningham
  • 2,949
  • 1
  • 23
  • 50
  • 1
    I think you should look at select again. It is not about freeing sockets but about detecting if new data are available and if data can be written, i.e. exactly what you need. Since SSL sockets and select is a bit more complex then normal sockets and select I suggest you start with the simpler case and add SSL later, after studying [How to handle OpenSSL SSL_ERROR_WANT_READ / WANT_WRITE on non-blocking sockets](http://stackoverflow.com/questions/3952104/how-to-handle-openssl-ssl-error-want-read-want-write-on-non-blocking-sockets) and other resources. – Steffen Ullrich Oct 02 '16 at 08:05
  • Possible duplicate: https://stackoverflow.com/questions/1543466/how-do-i-change-a-tcp-socket-to-be-non-blocking – Galik Oct 02 '16 at 08:13
  • You don't need non-blocking mode to handle multiple clients concurrently, and the O_NONBLOCK mechanism is extremely well-defined. Unclear what you're asking. – user207421 Oct 02 '16 at 09:34

1 Answers1

1

First, with server code, it's important to differentiate between concurrency and parallelism. A reasonable server will typically handle many more connections concurrently than its number of cores. Consequently, it's important to make the code concurrent in the sense that it can (efficiently) handle many concurrent connections, in a way that does not rely on parallelism (in the sense of having each connection handled by a thread).

In this sense, select is actually a reasonable choice for concurrency, and gives you the effect of being non-blocking.

When your system handles multiple sockets concurrently, select indicates on which socket(s) you can perform operations such as send and recv without their blocking when you do so. If you use select well you won't have cases where your thread is idling, waiting indefinitely for some operation to proceed, while other sockets are ready.

The minimal example from gnu.org shows a reasonably efficient server which it seems you can adapt to your needs.

fd_set active_fd_set, read_fd_set;
FD_ZERO (&active_fd_set);
FD_ZERO (&read_fd_set);

// Use FD_SET to add sockets according to what you want to do with them

/* This call (checking to see who can be read) is the 
* only thing that blocks. But if it does, no socket is ready for reading. */
if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0) {
    // Handle error;

for (i = 0; i < FD_SETSIZE; ++i)
    if (FD_ISSET (i, &read_fd_set))
        // Here you can read without its blocking.
Community
  • 1
  • 1
Ami Tavory
  • 74,578
  • 11
  • 141
  • 185