开发者

Sockets and threads using C

开发者 https://www.devze.com 2023-01-16 12:03 出处:网络
I am new to both sockets and threads. I have this code: listen(socket_fd, 20); /* Looooop */ while (1) {

I am new to both sockets and threads. I have this code:

listen(socket_fd, 20);

/* Looooop */
  while (1) {
    newsocket_fd = accept(socket_fd, 
                          (struct sockaddr *) &client_addr, 
                          &client_len);
    if (newsocket_fd < 0) {
      error("ERROR on accept");
    }
    pthread_t thread;
    pthread_create(&thread, NULL, run_thread, (void *) newsocket_fd);
    pthread_join(thread, NULL);
  }

How can I start a new thread for each new connection, rather than for each request? These threads should be started when a new connection comes in, and these threads should then wait for requests, handle those requests, and finally return开发者_运维问答 when the connection is closed. There should be one thread for each connection. Here is the code for run_thread:

void
*run_thread(void *ptr) {
  char buffer[256];
  bzero(buffer, 256);
  int n;
  n = read((int) ptr, buffer, 255);
  if (n < 0) error("ERROR Reading from socket");
  printf("%s\n\n**********\n\n", buffer);

  /* Parse buffer and return result */
  char *result;
  {
    /* First, determine command, 4 characters */
    /* (much code) */
  }

  n = write((int) ptr, result, strlen(result));
  if (n < 0) error("ERROR Writing to socket");
}

Can anyone help me? Thanks.


There is also a different critical error.

You cast the int to (void*). This does not make sense. Also, you can't pass the address directly since the variable could be changed on the next accept() call before the thread can copy the variable to its local stack. One way to write it would be something like this:

while (1) {
    newsocket_fd = accept(socket_fd, 
                          (struct sockaddr *) &client_addr, 
                          &client_len);
    if (newsocket_fd < 0) {
      error("ERROR on accept");
    }
    pthread_t thread;
    int *newsock = malloc(sizeof(int));
    *newsock = newsocket_fd;
    pthread_create(&thread, NULL, run_thread, newsock);
    pthread_detach(thread);
  }

With this approach, the thread will make sure to free() the newsock. E.g a simple

void *handler(void *thread_data) {
   int fd = *(int *) thread_data;
   free(thread_data);
   ....
}

Also, I assume pthread_detach() is okay, if the main program doesn't care about syncing up with the thread later with pthread_join().


You almost got it right. The problem is, however, that you are joining the thread right after creation, and pthread_join is actually a blocking call which is waiting for the thread to finish. It means that you will not be able to accept any more connections while that one thread is running. To solve this problem, you might want to use detached threads. You don't have to join detached threads. For this purpose, you have to create thread attributes using pthread_attr_init function and pass those attributes to pthread_create.

Be aware that if you have too many client connections, your application may run out of resources. So, in real world, you have to manage a pool of threads. But the best case scenario for TCP/IP server applications is to use asynchronous I/O. I do not know about C, but there is a very good library in C++ for asynchronous I/O application called boost::asio.


Vlad has good advice.

Also note that your newsocket_fd variable is being reused for each new connection in your accept loop, and then a pointer to it is passed to every worker thread. This will cause problems when you start having multiple clients connected at the same time.

EDIT: Ignore this comment, I misread the mistake you were making. Others have given proper corrections for your handling of newsocket_fd.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号