【问题标题】:Terminating client threads in a client-server setup using pthreads使用 pthreads 在客户端-服务器设置中终止客户端线程
【发布时间】:2024-04-20 13:55:02
【问题描述】:

我制作了一个简单的聊天服务器程序,它使用多个线程来处理多个客户端。一旦我启动我的服务器,许多客户端将连接到服务器,因此将创建多个线程。现在,有时我会关闭服务器。

所有创建的线程都会被销毁吗?如何检查任何线程是活着还是死了?我在 Linux 平台上工作。

服务器.c:

    //for running type ./a.out anyportnumber
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
int s2;
int arr[100];
int tc = 0;
int flag = 1;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void handler(int signal)
{
    flag = 0;
}
void sendtoall(char *msg,int s1)
{
    int i;
    pthread_mutex_lock(&mutex);
    for(i = 0; i < tc; i++) {
        if(arr[i] != s1) 
            write(arr[i],msg,strlen(msg));
    }
    pthread_mutex_unlock(&mutex);
}
void *function(void *s)
{
    int s1;
    int n;
    char rmsg[500];
    s1 = *(int *)s;
    while((n = read(s1,rmsg,500)) > 0) {
        if(flag == 0) {
            break;
        }
        rmsg[n] = '\0';
        sendtoall(rmsg,s1);
        bzero(rmsg,500);
    }
    pthread_exit(NULL);
}
int main(int arrc,char *argv[])
{
    struct sockaddr_in server,client;
    int s1,len;
    int n;
    int port;
    pthread_t t1;
    char message[500];
    port = atoi(argv[1]);
    bzero((char *)&server,sizeof(server));
    server.sin_port = htons(port);
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_family = AF_INET;
    s1 = socket(AF_INET,SOCK_STREAM,0);
    if(s1 == -1) {
        perror("socket not created\n");
        exit(1);
    }
    if(bind(s1,(struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
        perror("socket not binded\n");
        exit(1);
    }
    if(listen(s1,5) == -1) {
        perror("unable to listen");
        exit(1);
    }
    len = sizeof(struct sockaddr_in);
    signal(SIGINT, handler);
    while(1) {
        if(flag == 0) {
            break;
        }
        s2 = accept(s1,(struct sockaddr *)&client,&len);
        pthread_create(&t1,NULL,function,(void *)&s2);
        arr[tc] = s2;
        tc++;
    }
    close(s1);
    close(s2);
    return 0;

}

【问题讨论】:

  • 很难知道您是否不发布任何代码。可以吗?
  • 你如何“关闭服务器”?
  • 在终端中按 ctrl + c。

标签: c linux multithreading pthreads


【解决方案1】:

简短的回答是肯定的:当主进程退出时,所有线程也会死掉。

但在您的代码中,我没有看到任何“关闭”服务器。您只是在无限循环中创建线程,代码中有很多问题:

  • 不检查线程创建是否成功。
  • 可能会超出数组arr(只能处理100 个元素)。
  • 仅与最后创建的连接,这实际上是一个无法访问的语句。
  • 访问rmsg[n] = '\0';,这是 UB 的潜在候选者。如果 read(2) 读取 500 个字符,则 n 将是 500 并且 rmsg[n] = '\0'; 是越界访问。

【讨论】:

  • 一旦所有这些都修复了,对于我认为 OP 最初想要的一个很好的解决方案可能是在主线程中捕获 SIGINT,设置一些全局变量并使用它来打破 while 循环,并等待所有线程完成。
  • 您能建议一种在客户端与服务器断开连接时终止线程的方法吗?我如何知道客户端是否已断开连接?
  • @ShivamMitra 因为您为每个客户端创建一个线程并调用pthread_exit(0),所以该线程将终止。您不需要明确地“杀死”。一种建议是在线程函数中使用pthread_detach(pthread_self());,以便线程特定的数据结构在它死亡时被清除。您的主要问题是制定关闭服务器(该循环)的策略。如果您希望 ctrl+c 作为关闭机制,您可以捕获 SIGINT。或者你可以让服务器处理固定数量的客户端,如果超过了就等到一些客户端关闭。
  • @ShivamMitra 这是一个simple example I wrote 来捕获SIGINT(这是在 Linux 上为 ctrl+c 生成的)。但如前所述,您应该决定服务器是需要处理尽可能多的请求还是只需要处理固定数量的客户端并相应地重写您的代码。
  • 我会实施的。但我有一个问题。一旦我按下 ctrl+c,这个过程无论如何都会被终止。那么 SIGINT 有什么用呢?