简体   繁体   中英

Socket Server Hangs

This socket server has some error in it, most likely pthread related. If this keeps accepting client connections, after a while it will start hanging. It doesn't seems to be a memory leak because the memory occupied by the program remains the same but when I connect with a telnet client it will just hang and does not do anything.

It will still get to the puts("Handler assigned"); part but then it does nothing. Any ideas what can cause this?

/*
    C socket server example, handles multiple clients using threads
*/

#include<stdio.h>
#include<string.h>    //strlen
#include<stdlib.h>    //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h>    //write
#include<pthread.h> //for threading , link with lpthread

//the thread function
void *connection_handler(void *);

int main(int argc , char *argv[])
{
    int socket_desc , client_sock , c , *new_sock;
    struct sockaddr_in server , client;

    //Create socket
    socket_desc = socket(AF_INET , SOCK_STREAM , 0);
    if (socket_desc == -1)
    {
        printf("Could not create socket");
    }
    puts("Socket created");

    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( 8888 );

    //Bind
    if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
    {
        //print the error message
        perror("bind failed. Error");
        return 1;
    }
    puts("bind done");

    //Listen
    listen(socket_desc , 3);

    //Accept and incoming connection
    puts("Waiting for incoming connections...");
    c = sizeof(struct sockaddr_in);


    //Accept and incoming connection
    puts("Waiting for incoming connections...");
    c = sizeof(struct sockaddr_in);
    while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
    {
        puts("Connection accepted");

        pthread_t sniffer_thread;
        new_sock = malloc(1);
        *new_sock = client_sock;

        if( pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) new_sock) < 0)
        {
            perror("could not create thread");
            return 1;
        }

        //Now join the thread , so that we dont terminate before the thread
        //pthread_join( sniffer_thread , NULL);
        puts("Handler assigned");
    }

    if (client_sock < 0)
    {
        perror("accept failed");
        return 1;
    }

    return 0;
}

/*
 * This will handle connection for each client
 * */
void *connection_handler(void *socket_desc)
{
    //Get the socket descriptor
    int sock = *(int*)socket_desc;
    int read_size;
    char *message , client_message[2000];

    //Send some messages to the client
    message = "Greetings! I am your connection handler\n";
    write(sock , message , strlen(message));

    message = "Now type something and i shall repeat what you type \n";
    write(sock , message , strlen(message));

    //Receive a message from client
    while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
    {
        //Send the message back to client
        write(sock , client_message , strlen(client_message));
    }

    if(read_size == 0)
    {
        puts("Client disconnected");
        fflush(stdout);
    }
    else if(read_size == -1)
    {
        perror("recv failed");
    }

    //Free the socket pointer
    free(socket_desc);

    return 0;
}
  1. Don't assume that writing to a socket writes all bytes. Always check the return value. Instead of write use your own sendbuf() function that writes to the socket in a loop and returns only when all bytes of your buffer has been sent.`
  2. You have to join every created thread exactly once otherwise you leak a thread handle. If you don't want to join a thread then you have 2 options:
    1. Create it as detached by specifying the attribute parameter for pthread in which you tell pthread_create() to create the thread as detached. Search for tutorials that use the pthread_attr_setdetachstate() function to find out how to do this.
    2. After creating the thread call pthread_detach() on it to tell the pthread library that you don't want to join the thread.
  3. Since you receive and send in turns if both the server and the client are using blocking sockets it may happen that the send buffers fill up on both ends if the client tries to send a large enough buffer and it results in a deadlock. Aid this with one of the following solutions:
    1. Use setsockopt() in your server to setup send/receive timeouts with the SO_SNDTIMEO and SO_RCVTIMEO socket options and optionally tweak the send/receive buffer sizes with SO_SNDBUF SO_RCVBUF options if you want but I wouldn't set these latter two options without reasons.
    2. At least one of the peers (preferably the server) should receive and send at the same time using asnyc socket.
  4. Use read_size instead of strlen(client_message) when sending back the message to the client. Assuming that the received chunk is zero terminated is wrong even if the client has sent a zero terminated message because you may receive it as fragmented.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM