处理多个客户端时,pthread_join在分叉TCP服务器时失败

处理多个客户端时,pthread_join在分叉TCP服务器时失败,c,tcp,client-server,C,Tcp,Client Server,我必须创建一个多线程TCP/IP服务器,其中包含一个变量,用于计算连接的客户端(以及断开连接的客户端)数量,并在客户端连接到服务器时打印连接的客户端数量 这是我的client.c文件: #定义端口4444 int main() { int客户端套接字; serverAddress中的结构sockaddr_; 字符缓冲区[1024]; ssize_t nread; clientSocket=socket(AF\u INET,SOCK\u STREAM,0); if(clientSocket==-1

我必须创建一个多线程TCP/IP服务器,其中包含一个变量,用于计算连接的客户端(以及断开连接的客户端)数量,并在客户端连接到服务器时打印连接的客户端数量

这是我的client.c文件:

#定义端口4444
int main()
{
int客户端套接字;
serverAddress中的结构sockaddr_;
字符缓冲区[1024];
ssize_t nread;
clientSocket=socket(AF\u INET,SOCK\u STREAM,0);
if(clientSocket==-1){
perror(“[-]Errore durante la creazione della socket\n”);
出口(-1);
}
printf(“[+]客户端套接字已创建\n”);
memset(&serverAddress,'\0',sizeof(serverAddress));
serverAddress.sin_family=AF_INET;
serverAddress.sin_port=htons(端口);
serverAddress.sin\u addr.s\u addr=INADDR\u ANY;
if(connect(clientSocket,(struct sockaddr*)&serverAddress,sizeof(serverAddress))=-1){
perror(“连接错误”);
出口(-1);
}
而(1){
printf(“>”);
fflush(stdin);
scanf(“%s”,缓冲区);
如果(nread!=-1)
缓冲区[nread]='\0'*/
如果(发送(客户端套接字、缓冲区、strlen(缓冲区)、0)=-1){
佩罗(“因维奥的错误”);
出口(1);
}
if(strcmp(缓冲区“:退出”)==0{
关闭(clientSocket);
printf(“[-]已断开与服务器的连接\n”);
出口(0);
}
if((nread=recv(clientSocket,buffer,sizeof buffer-1,0))clientCollegati);
child=fork();
如果(子项==0){
关闭(服务器插座);
而(1){
如果((nread=recv(clientSocket,buffer,sizeof buffer-1,0))clientCollegati=0;
ptr->clientCheSiSonoScollegati=0;
pthread_mutex_init(&ptr->mutex,NULL);//nizalizazione dinamica del mutex
返回ptr;
}
无效*增量A(无效*ptr)
{
pthread_mutex_lock(&test->mutex);
测试->客户端Collegati++;
pthread_mutex_unlock(&test->mutex);
pthread_退出(0);
}
不幸的是,这似乎不能正常工作,你可以看到这里和这里

  • 错误在哪里?我想问题是当tid完成时,对该
    pthread\u join
    的第二次调用被调用到一个不存在的线程(因为只有一个线程)

您的代码逻辑错误。您正在执行一个
pthread\u create()
,然后执行多个
pthread\u join()
。如果要为每个连接的客户端增加值,则必须在每次成功执行
accept()
后执行一个
pthread\u create()
,然后执行一个
pthread\u join()
。注意:所有这些都必须在调用
fork()
之前发生

错误在哪里?我想问题是当
tid
finish时,对该
pthread\u join
的第二次调用被调用到一个不存在的线程(因为只有一个线程)

这正是发生的情况。在当前程序中,第一个
pthread\u join()
是成功的,任何后续调用都会失败,错误为errno 3(没有这样的进程),因为该线程不再存在。因此,您已经明白了这一点。如果您知道这是错误的,为什么要创建一个线程,但要多次加入它

程序的编写方式(增量后的fork)也就是说,实际上根本没有理由使用线程进行增量,而且您甚至不需要互斥,因为在任何给定时间只有一个线程将访问该值。换句话说,您的服务器根本不是多线程的。如果您只想将此作为一个实验来进行,这也没关系,但没有多大意义


您可能想要做的(使用多线程服务器)是让每个客户端有一个线程,而不是每次使用线程函数中的客户端代码进行分叉(在这种情况下,使用互斥锁是有意义的)。但请注意,这对于大量客户端(通常是经典的
fork()
方法更好,在这种情况下,你真的不需要任何线程)。

pthread_join返回的错误代码是什么?你知道线程做什么吗?它返回3…strerror(3)是什么?我编辑了你的问题标题以使它更清楚。fork()方法不是最好的,因为创建了一个进程(在PID意义上)在系统资源(特别是内存)方面要求更高,在不忘记从父进程复制数据的成本的情况下,…多线程方法更轻,因此更有效。选择基于fork的方法应该有多线程方法无法满足的约束mode@Landstalker多线程方法在现实中很少使用,因为它不提供isol由于线程的调度不同于进程,最重要的是系统限制,例如每个进程打开的文件描述符的数量很容易被超过。一个分叉服务器在
accept()
之后执行不同的(更轻的)命令客户端进程是实现多客户端TCP服务器的事实上的标准方式。这是我试图表达的观点。当然,根据场景的不同,多线程仍然很有用。如果您正在寻找一个简单的解决方案,fork是最好的方法,因为默认情况下内存空间是分开的(不同的堆,不同的堆栈,…)但是,如果您正在寻找性能,系统资源的优化,…多线程更合适(但管理更复杂)。您只需将FORK的时间与创建线程的时间进行比较,再加上垄断资源的数量……必须根据需要合理使用FORK。在选择FORK之前,您必须问自己一个问题,多线程是否允许我这样做?
#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;
}
#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);

}