Сбой pthread_join при разветвлении TCP-сервера при работе с несколькими клиентами - PullRequest
0 голосов
/ 14 февраля 2020

Мне нужно создать многопоточный сервер TCP / IP, который содержит переменную для подсчета количества подключенных клиентов (и тех, которые отключаются) и печати количества клиентов, подключенных при подключении клиента к серверу.

Это мой клиент. c файл:

#define PORT 4444

int main ()
{
    int clientSocket;
    struct sockaddr_in serverAddress;
    char buffer[1024];
    ssize_t nread;

    clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (clientSocket == -1) {
        perror("[-]Errore durante la creazione della socket\n");
        exit(-1);
    }
    printf("[+]Client socket has been created\n");


    memset(&serverAddress, '\0', sizeof(serverAddress));

    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(PORT);
    serverAddress.sin_addr.s_addr = INADDR_ANY;

    if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
        perror("Errore con la connessione\n");
        exit(-1);
    }

    while (1) {

        printf("> ");
        fflush(stdin);
        scanf("%s", buffer);

        if (nread != -1)
            buffer[nread] = '\0';*/

        if (send(clientSocket, buffer, strlen(buffer), 0) == -1) {
            perror("Errore con l'invio");
            exit(1);
        }

        if(strcmp(buffer, ":exit") == 0) {
            close(clientSocket);
            printf("[-]Disconnected from Server\n");
            exit(0);
        }

        if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
            perror("[-]Error in receiving data from server\n");
        }
        else {
            buffer[nread] = '\0';
            printf("Server received: %s\n", buffer);
        }

    }

    close(clientSocket);

    return 0;
}

, а это мой сервер. c файл:

#define PORT 4444
#define MAX_CONNESSIONI 100

typedef struct myStruct {
    int clientCollegati;
    int clientCheSiSonoScollegati;
    pthread_mutex_t mutex; // Creazione del mutex per sincronizzare la struttura
} myStruct;

myStruct *test; 

myStruct *initStruct();
void *incrementa(void*);

int main ()
{
    int serverSocket, bindStatus;
    struct sockaddr_in serverAddress;
    int clientSocket;
    struct sockaddr_in newAddress;
    char buffer[1024];
    pid_t child;
    socklen_t addrSize;
    ssize_t nread;
    pthread_t tid;

    test = initStruct(); 

    if (pthread_create(&tid, NULL, incrementa, NULL) != 0) {
        perror("Errore nella creazione del thread t1\n");
        exit(1);
    }
    serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket == -1) {
        perror("[-]Errore durante la creazione della socket\n");
        exit(-1);
    }


    memset(&serverAddress, '\0', sizeof(serverAddress));

    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(PORT);
    serverAddress.sin_addr.s_addr = INADDR_ANY;
    bindStatus = bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
    if (bindStatus == -1) {
        perror("[-]Errore durante il binding\n");
        exit(1);
    }
    printf("[+]Bind to port %d\n", PORT);


    if (listen(serverSocket, MAX_CONNESSIONI) != -1) {
        printf("Listening . . .\n\n");
    }
    else {
        perror("[-]Error during listening\n");
        exit(1);
    }


    while (1) {

        clientSocket = accept(serverSocket, (struct sockaddr*)&newAddress, &addrSize);
        if (clientSocket == -1) {
            exit(-1);
        }
        printf("%s:%d joined\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));

        if (pthread_join(tid, NULL)) { // returns 3
            perror("pthread_join error\n");
            exit(1);
        }

        printf("There is/are %d client(s) connected\n", test->clientCollegati);

        child = fork();
        if (child == 0) {

            close(serverSocket);

            while (1) {

                if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
                    perror("[-]Error in receiving data from server\n");
                }
                else {
                    buffer[nread] = '\0';
                }


                if (strcmp(buffer, ":exit") == 0) {
                    printf("%s:%d left\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));
                    break;
                }
                else {
                    printf("%s:%d wrote: %s\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port), buffer);
                    send(clientSocket, buffer, strlen(buffer), 0);
                    bzero(buffer, sizeof(buffer));
                }

            }

        }

    }

    close(clientSocket);

    return 0;
}

myStruct *initStruct()
{
    struct myStruct *ptr = malloc(sizeof(myStruct));

    ptr->clientCollegati = 0;
    ptr->clientCheSiSonoScollegati = 0;

    pthread_mutex_init(&ptr->mutex, NULL); // inizializzazione dinamica del mutex

    return ptr;

}

void *incrementa(void *ptr)
{

    pthread_mutex_lock(&test->mutex); 


    test->clientCollegati++;


    pthread_mutex_unlock(&test->mutex);

    pthread_exit(0);

}

К сожалению, это, кажется, не работает должным образом, и вы можете видеть вывод сервера и здесь client1 и здесь выход client2

  • Где ошибка? Я предполагаю, что проблема в том, что tid fini sh и второй вызов этого pthread_join вызывается в несуществующий поток (потому что существует один поток)

1 Ответ

0 голосов
/ 14 февраля 2020

Ваш код логи c неверен. Вы делаете один pthread_create(), а затем несколько pthread_join(). Если вы хотите увеличить значения для каждого подключенного клиента, вы должны сделать один pthread_create() после каждого успешного accept(), а затем один pthread_join(). Примечание: все это должно произойти до вызова fork().

Где ошибка? Я предполагаю, что проблема в том, что tid fini sh и второй вызов этого pthread_join вызывается в несуществующий поток (потому что существует один поток)

Это точно что просходит. В вашей текущей программе первый pthread_join() успешен, и любой последующий вызов завершается с ошибкой 3 (такого процесса нет), потому что поток больше не существует. Итак, вы уже поняли это. Почему вы создаете один поток, но присоединяетесь к нему несколько раз, если знаете, что это неправильно?

Способ написания вашей программы (разветвление после приращения) также означает, что на самом деле нет никакой причины использовать потоки для выполнения инкремент, и вам даже не нужен мьютекс, поскольку только один единственный поток будет иметь доступ к значению в любой момент времени. Другими словами, ваш сервер не является многопоточным. Если вы хотите сделать это только в качестве эксперимента, это нормально, но в этом нет особого смысла.

Что вы, вероятно, хотите сделать (иметь многопоточный сервер), это иметь один поток на клиента вместо разветвления каждый раз с клиентским кодом в функции потока (в этом случае иметь мьютекс имеет смысл). Однако следует помнить, что это плохо масштабируется для большого числа клиентов (в общем случае классический подход fork() лучше, и в этом случае вам действительно не нужен поток).

...