简体   繁体   中英

server stops creating threads

I have a very simple client-server code. Every time a server receives a packet I create a thread that handles it. The code is shown below. What I can't understand is that after sometime my server stops receiving any data. It just listens and doesn't receive anything. I can't figure out why. Does anyone know the reason.

I'm building my code on Lenovo T470s Fedora 29, Linux user 4.19.15-300.fc29.x86_64 #1 SMP Mon Jan 14 16:32:35 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Any help is appreciated.

/* 
  server.c
  cc -std=gnu11 -pedantic  -lpthread  server.c   -o server.c 
 */

#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <poll.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define BUF_SIZE_B 1024

static int fd;

static void *handlePacketThreadWrapper(void *arg);

int main(void)
{
    pthread_t t;
    struct pollfd pollfd;
    struct sockaddr_in addr;
    uint16_t port = 9500;

    fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    if (fd < 0)
    {
        printf("errno: %d. %s. Failed to create a socket",
                errno, strerror(errno));
        exit(EXIT_FAILURE);
    }

    addr.sin_family      = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port        = htons(port);

    while(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        printf("errno: %d. %s. Failed to bind socket. Will attempt again.", errno,
                strerror(errno));
        sleep(1);
    }

    memset(&addr, 0, sizeof(addr));

    pollfd.fd = fd;
    pollfd.events = POLLIN;

    while(true)
    {

        if (poll(&pollfd, 1, -1) < 0)
        {
            printf("errno: %d. %s", errno, strerror(errno));
        }
        else
        {
            pthread_create(&t, NULL, handlePacketThreadWrapper, NULL);
        }
    }

    return 0;
}

static void *handlePacketThreadWrapper(void *arg)
{
    uint8_t buf[BUF_SIZE_B];
    size_t strLen, fullIPLen;
    ssize_t
        i,
        n
        ;
    struct sockaddr_in addr;
    socklen_t addrLen = sizeof(addr);
    char *str, *fullIP;


    n = recvfrom(fd, buf, sizeof(buf), 0,
            (struct sockaddr *)&addr, (socklen_t *)&addrLen);
    if (n < 0)
    {
        printf("errno: %d. %s. Failed to create a socket",
                errno, strerror(errno));
    }
    else
    {
        for (i = 0; i < n; i++)
        {
            printf("0x%02X ", buf[i]);
        }
        printf("\n");
    }
    return NULL;
}

And here is my client code:

/* 
  client.c
  cc -std=gnu11 -pedantic  client.c   -o client.c  
 */
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>

#define BUF_SIZE_B 1024

int main(void)
{
    ssize_t size, i;
    struct sockaddr_in dest;
    int fd;
    char *toIP = "127.0.0.1";
    uint16_t toPort = 9500;
    uint8_t buf[BUF_SIZE_B];

    fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (fd < 0)
    {
        printf("errno: %d, %s", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }

    memset(&dest, 0, sizeof(dest));
    dest.sin_family      = AF_INET;
    dest.sin_addr.s_addr = inet_addr(toIP);
    dest.sin_port        = htons(toPort);

    while(true)
    {
        size = sendto(fd, buf, sizeof(buf), 0, (struct sockaddr*)&dest, sizeof(dest));
        if (size < 0)
        {
            printf("errno: %d. %s. Failed to send bytes to %s:%hu.", 
                    errno, strerror(errno), toIP, toPort);
        }
        else
        {
            for (i = 0; i < size; i++)
                printf("0x%02X ", buf[i]);
            printf("\n");
        }
        usleep(1000);
    }

    return 0;
}

You can only have as many threads running simultaneously, as ulimit -u reports.

Your server never joins the threads, and once the limit is reached it starts failing to create them.

In your server the main thread and the created thread(s) access the same socket ( fd ) without any protection like exclusive section, so the execution of poll and recvfrom can be done in any order including simultaneously , that probably destruct the internal data of the socket.

You can do for example :

while(true)
{

    if (poll(&pollfd, 1, -1) < 0)
    {
        printf("errno: %d. %s", errno, strerror(errno));
    }
    else
    {
        pthread_create(&t, NULL, handlePacketThreadWrapper, NULL);
        pthread_join(&t);
    }
}

That both protect the use of the socket and avoid zombie thread as mentioned by user58697 in an other answer (the threads are not detached by default).

Of course doing that limit the interest to read on the socket in an other thread, but your code is not really compatible with multi threading for several reasons

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