1

I'm designing a multi-threaded server with a thread pool. This system is designed to use persistent TCP connections, as clients will maintain connects close to 24/7. The problem I run into is how to manage shutdowns. Currently, a connection comes in through "accept(listen_fd....)" and gets assigned to a work order struct. This struct is dumped onto the work queue, and is picked up by a thread. From this point on, this thread is devoted to the current connection. My code inside the thread is:

/* Function which runs in a thread to handle a request */
void *
handle_req( void *in)
{
  ssize_t n;
  char read;
  /* Convert the input to a workorder_ptr */
  workorder_t *workorder_ptr = (workorder_t *)in;

  while( !serv_shutdown
        && (n=recv(workorder_ptr->sock_fd,&read,1,0) != 0))
  {
    printf("Read a character: %c\n",read);
  }
  printf("Peer has shutdown.\n");

  /* Free the workorder memory */
  close(workorder_ptr->sock_fd);
  free(workorder_ptr);
  return NULL;
}

Which simply listens to the socket and echos the characters indefinitely, and operates correctly when the client terminates the connection. You see the "!serv_shutdown" part in the while loop - this is my attempt to get the thread to break out of its loop on a shutdown signal. When a SIGINT is caught, the global variable is set to 1. Unfortunately, the program is currently blocking on the recv statement, and won't check this flag until another character is read. I want to avoid that, since it could be an arbitrary amount of time before another character is sent on this connection.

Also, I read on another post here that it's better to use "select" than "accept" to wait on a socket connection, but I didn't quite understand. Would you do a select to wait, and then do an accept right after that? I'm not sure how select creates a socket connection. I ask this, because if my understanding of select is cleared up, maybe it applies to the question I am asking?

Also also, how do I detect the case where a connection simply times out?

Thanks!

EDIT I think I may have finally found a solution, after further digging:

Wake up thread blocked on accept() call

Basically, I could create a global pipe and have each thread do a select on its own socket_fd as well as this global pipe. Then, when a signal is caught, I'll just write something to the pipe. All threads should be woken, no?

Community
  • 1
  • 1
theseankelly
  • 51
  • 1
  • 7

2 Answers2

1

Well, on FreeBSD, MacOSX and maybe somewhere else there is kevent() call, that allows listening on a broad range of system events including connect requests and signaling when data arrives to the socket. It will solve all of your problems in a neat way, but it's not portable. There are libs such libevent and libev, that wraps OS-specific functionality like kevent() on BSD's, epoll() on Linux and so on. May be it would help you.

arrowd
  • 33,231
  • 8
  • 79
  • 110
1

You can use the recv() primitive. If it returns 0, that means that the socket has been closed.

More information: http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#recvman

NullUserException
  • 83,810
  • 28
  • 209
  • 234
makotaum
  • 11
  • 1