C 中客户端之间的 ChatRoom 服务 - TCP

ChatRoom Service between Clients in C - TCP

开始吧,我想做的是多客户端聊天服务。 我已经阅读了数千篇与之相关的帖子,但其中大部分都是用线程实现的,对我没有任何帮助,我需要使用 FORKS 来完成。

我的服务器支持多客户端连接。每次客户端请求连接时,服务器都会执行以下操作:

  1. 设置所需的共享变量。
  2. 获取正确的套接字来处理连接,
  3. 当客户端连接时,将客户端的数据保存在用结构体实现的客户端数组中,
  4. 派生一个进程来处理这个连接,
  5. 返回并阻塞在等待另一个客户端的 accept() 函数中。

分叉执行以下操作:

  1. 等待用户发送的命令,
  2. 完成请求,
  3. 等待另一个命令。 该分支与受信号量保护的共享客户端数组一起工作。这是(由父进程)使用 shm_open、mmap 和 shm_open 完成的,以便在子进程之间共享数组。

目前只有 3 个选项:

  1. clientlist : 查看连接的客户端列表,
  2. sendchat : 向所需的客户端发送消息,
  3. quit_ : 退出程序并断开与服务器的连接。

话虽如此,问题是我无法以任何方式通知客户消息已准备好发送给他。执行流程为:

  1. 客户端 C1 连接,客户端 C2 连接。
  2. C1 想向 C2 发送消息,C1 告诉他的进程他想与 C2 交谈。
  3. 处理C1连接的进程,在共享数组中查找C2的名称,然后将C1发送的消息写入C2的缓冲区。
  4. 这就是我卡住的地方..我不知道如何让 C2 通知这是给 im 的新消息。

我知道这对任何人来说都太长了,但如果可以的话,我很乐意得到一些帮助。

以下是客户端和服务器脚本。

注意: server.c 编译时使用-lptrhead 和-lrt 绑定共享内存库。

注意: 服务器从函数 get_tcp_listen 中正确获取套接字,如您所见,无需担心关于这个。

我该如何解决这个问题?谢谢!

client.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include "socketlib.h" // FOR BINDINGS, GET SOCKET, AND STUFF

#define SERVER_PORT "50000"
#define CLIENT_PORT "50001"
#define MAXDATASIZE 256
#define MAXTIMESIZE 30
#define NICKSIZE 25
#define MAXCLIENT 10
#define MAXMSG 1024

typedef struct{
    char nick[NICKSIZE];        // NICK
    char ip[NI_MAXHOST];        // IP
    char port[NI_MAXSERV];      // PORT
    char connTime[MAXTIMESIZE]; // TIMESTAMP
    int connected;              // STATE
    pid_t pidConn;              // PROCESS PID 
    char *msg;          // MSG BUFFER
}connData;


int main (int argc, char **argv) {

    // GET SOCKET
    int sockfd;
    if ((sockfd = get_tcp_connect(argv[1], SERVER_PORT, CLIENT_PORT)) == -1) {
        fprintf(stderr, "Error client: client_connect\n");
        exit(1);}
    ///////////////////////////////////////////////////////////////////////
    time_t ltime;
    ltime = time(NULL);
    char timeStamp[MAXTIMESIZE];
    strcpy(timeStamp,ctime(&ltime));
    printf("\n%s\n", timeStamp);

    // GET MY IP : PORT
    char ip_num[NI_MAXHOST];
    char port_num[NI_MAXSERV];
    get_socket_addr(sockfd, ip_num, port_num);
    get_peer_addr(sockfd, ip_num, port_num);
    ///////////////////////////////////////////////////////////////////////


    // WELLCOME MSG FROM SERVER
    char *well = (char*) malloc(MAXDATASIZE); int numbytes;
    if ((numbytes = recv(sockfd, well, MAXDATASIZE-1, 0)) == -1) {
            fprintf(stderr, "Error client: recv WELLCOME\n");
            exit(1);
    }
    well[numbytes] = '[=10=]'; printf("%s\n", well); free(well);
    //////////////////////////////////////////////////////////////////////


    // SEND NICK TO SERVER
    char nick[NICKSIZE];
    printf("\nEnter your NickName (25 chars): "); scanf("%s",nick); 
    if(send(sockfd, nick, NICKSIZE, 0) == -1){
        fprintf(stderr,"Error client: send NICK\n");
        exit(1);
    }
    ///////////////////////////////////////////////////////////////////////


    // GET CONNECTED USERS LIST FROM SERVER
    int cantClients = 0; // FIRST: QUANTITY OF USERS
    if (recv(sockfd, &cantClients, sizeof(int), 0) == -1) {
        fprintf(stderr, "Error client: recv CANT CLIENTs\n");
        exit(1);
    }
    connData *tmpCl = (connData *) malloc(sizeof(connData)*MAXCLIENT);
    if (recv(sockfd, tmpCl, sizeof(connData)*MAXCLIENT, 0) == -1) {
        fprintf(stderr, "Error client: recv ARRAY CLIENTS\n");
        exit(1);
    }

    printf("\n****\tConnected Users\t****\n");
    int i;  
    for(i = 0; i < cantClients; i++){
        if(tmpCl[i].connected == 1){
            printf("\nNick: %s\n", tmpCl[i].nick); 
            printf("IP: %s\n", tmpCl[i].ip);
            printf("PORT: %s\n", tmpCl[i].port); 
            printf("Time: %s", tmpCl[i].connTime);
            printf("Connected: %d\n", tmpCl[i].connected);
            printf("PID: %d\n", tmpCl[i].pidConn);
            printf("**********************************\n");
        }
    } free(tmpCl);
    ///////////////////////////////////////////////////////////////////////


    // THE CLIENT PROCESS WAITS UNTIL THE USER TYPES A COMMAND
    char *comm = (char*)malloc(MAXDATASIZE);
    printf("\nEnter one option: "); 
    printf("\n\t-> clientlist TO SEE THE LIST OF CONNECTED CLIENTS\n");
    printf("\t-> sendchat TO SEND A MESSAGE\n");
    printf("\t-> quit_ TO QUIT CHAT\n>> ");
    scanf("%s",comm);

    int exitvar = 0;
    while(exitvar == 0){
            // PARA TRAER DATOS DEL SERVIDOR, ENVIO EL COMANDO, Y ME QUEDO ESPERANDO
            if(send(sockfd, comm, MAXDATASIZE-1, 0) == -1){
                fprintf(stderr,"Error client: send\n");
                exit(1);
            }

            if(strcmp(comm,"clientlist") == 0){
                // GET CONNECTED USERS LIST FROM SERVER
                connData *tmpCl = (connData *) malloc(sizeof(connData)*MAXCLIENT);
                if (recv(sockfd, tmpCl, sizeof(connData)*MAXCLIENT, 0) == -1) {
                    fprintf(stderr, "Error client: recv ARRAY CLIENT\n");
                    exit(1);
                }
                printf("\n****\tConnected Users\t****\n"); int i;
                cantClients = (unsigned) sizeof(*tmpCl) / (unsigned) sizeof(connData);
                for(i = 0; i < MAXCLIENT; i++){
                    if(tmpCl[i].connected == 1){
                        printf("\nNick: %s\n", tmpCl[i].nick); 
                        printf("IP: %s\n", tmpCl[i].ip);
                        printf("PORT: %s\n", tmpCl[i].port); 
                        printf("Time: %s", tmpCl[i].connTime);
                        printf("Connected: %d\n", tmpCl[i].connected);
                        printf("PID: %d\n", tmpCl[i].pidConn);
                        printf("**********************************\n");
                    }
                } free(tmpCl);
            }else if(strcmp(comm,"sendchat") == 0){
                printf("To whom you want to talk?... ");
                char *chatNick = (char *) malloc(NICKSIZE); 
                fgets(chatNick, NICKSIZE, stdin); 
                fgets(chatNick, NICKSIZE, stdin); 

                if((strlen(chatNick)>0) && (chatNick[strlen(chatNick)-1] == '\n') ){
                    chatNick[strlen(chatNick)-1] = '[=10=]';
                }

                if(send(sockfd, chatNick, NICKSIZE, 0) == -1){
                    fprintf(stderr, "Error client: send CHAT NICK\n");
                } 

                printf("Type your message...\n");
                char *chat_msg = (char *) malloc(MAXMSG); 
                fgets(chat_msg,MAXMSG,stdin) ;

                if((strlen(chat_msg)>0) && (chat_msg[strlen(chat_msg)-1] == '\n') ){
                    chat_msg[strlen(chat_msg)-1] = '[=10=]';
                }

                if(send(sockfd, chat_msg, MAXMSG, 0) == -1){
                    fprintf(stderr, "Error client: send CHAT\n");
                }

                free(chatNick);
                free(chat_msg);


            }else{
                char *buf = (char*) malloc(MAXDATASIZE); int numbytes;
                if ((numbytes = recv(sockfd, buf, MAXDATASIZE, 0)) == -1) {
                    fprintf(stderr, "Error client: recv\n");
                    exit(1);
                }
                buf[numbytes] = '[=10=]'; printf("-> %s\n", buf);
                free(buf);
            }

            if(strcmp(comm, "quit_") != 0){
                free(comm); comm = (char*)malloc(MAXDATASIZE);
                printf("\nWhats next?... "); scanf("%s",comm); 
            }else{
                close(sockfd);
                exitvar = 1;
            }
    }

    return 0;
}

server.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>  
#include <netdb.h>
#include <time.h>
#include "socketlib.h" 
#include <semaphore.h>

#define SERVER_PORT "50000"
#define BACKLOG 10 
#define MAXDATASIZE 256
#define NICKSIZE 25
#define MAXCLIENT 10
#define MAXTIMESIZE 30
#define MAXMSG 1024

// ESTRUCTURA QUE MANEJARA LA LISTA DE CLIENTES
typedef struct{
    char nick[NICKSIZE];        // NICK
    char ip[NI_MAXHOST];        // IP
    char port[NI_MAXSERV];      // PORT
    char connTime[MAXTIMESIZE]; // TIMESTAMP
    int connected;              // STATE
    pid_t pidConn;              // PROCESS PID 
    char *msg;          // MSG BUFFER
}connData;


// NOT ZOMBIE PROCESSES
void sigchld_handler(int s) {
    while (waitpid(-1, NULL, WNOHANG) > 0);
}

connData *client;
int *id; 

int main (int argc, char **argv) {


    // THE ARRAY OF CLIENTS IS SHARED BETWEEN THE PROCESSES
    int smid = shm_open("shm1", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    ftruncate(smid, sizeof(connData)*MAXCLIENT);

    // JUST FOR MAXCLIENT 10 CLIENTS AT THE MOMMENT
    client = mmap(NULL, sizeof(connData)*MAXCLIENT, PROT_READ | PROT_WRITE, MAP_SHARED, smid, 0);
    sem_t *sem; sem = sem_open("sem1", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, 1);


    // THE ARRAY INDEX IS ALSO SHARED
    int smid2 = shm_open("shm2", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    ftruncate(smid2, sizeof(int));

    id = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, smid2, 0);
    sem_t *sem2; sem2 = sem_open("sem2", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, 1);

    sem_wait(sem2);
    *id = 0;
    sem_post(sem2);


    // CONN CONFIG  
    struct sigaction sa;
    sa.sa_handler = sigchld_handler; 
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;

    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        fprintf(stderr, "Error server: sigaction\n");
        exit(1);
    }

    int sockfd; // LISTENER
    if ((sockfd = get_tcp_listen(SERVER_PORT, BACKLOG)) == -1) {
        fprintf(stderr, "Error get_tcp_listen\n");
        exit(1);
    }
    printf("server: waiting for connections...\n");

    char ip_num[NI_MAXHOST];
    char port_num[NI_MAXSERV];
    get_socket_addr(sockfd, ip_num, port_num);
    //////////////////////////////////////////////////////////////////


    while (1) {

        // BLOCKS UNTIL SOMEONE REQUEST CONN
        int new_fd;
        if ((new_fd = accept(sockfd, NULL, NULL)) == -1) {
            fprintf(stderr, "Error server: accept\n");
            continue;}
        ////////////////////////////////////////////////////////

        // IP:PORT OF JUST CONNECTED USER
        get_socket_addr(new_fd, ip_num, port_num);      
        get_peer_addr(new_fd, ip_num, port_num);
        printf("server: got connection from: %s, %s\n", ip_num, port_num);
        ////////////////////////////////////////////////////////

        // TIMESTAMP OF USER CONN
        time_t ltime; ltime = time(NULL);
        char timeStamp[MAXTIMESIZE]; strcpy(timeStamp,ctime(&ltime));
        ////////////////////////////////////////////////////////////////////////


        // WELLCOME MESSAGE SENT TO THE CLIENT
        char *well = (char*) malloc(MAXDATASIZE);
        if (send(new_fd, "Wellcome to the Chat Service!!\n", MAXDATASIZE-1, 0) == -1) {
            fprintf(stderr, "Error sending WELLCOME\n");
        } free(well);
        ///////////////////////////////////////////////////////////////

        // SAVES IN THE ARRAY OF CLIENTS, THE DATA OF THE CLIENT THAT JUST CONNECTED
        int idTmp1;
        sem_wait(sem2);
        idTmp1 = *id;
        sem_post(sem2);

        if(sem_wait(sem) == 0){
            strcpy(client[idTmp1].ip, ip_num);  // IP
            strcpy(client[idTmp1].port, port_num); // PORT
            strcpy(client[idTmp1].connTime, timeStamp); // TIMESTAMP
            client[idTmp1].connected = 1;
        }else{
            fprintf(stderr, "Error SEM_WAIT\n");
        }
        sem_post(sem);  

        sem_wait(sem2); (*id)++; sem_post(sem2);        

        //////////////////////////////////////////////////////////////


        // FORKS A PROCESS TO DEAL WITH THE JUST CONNECTED USER
        if (fork() == 0) { 
            close(sockfd); // CLOSES THE FATHERS SOCKET
            int numbytes = 0;

            // SAVES THE NICK IN THE ARRAY
            char userNick[NICKSIZE];
            if(( numbytes = recv(new_fd, userNick, NICKSIZE, 0)) == -1){
                fprintf(stderr,"Error rcv\n");
            } userNick[numbytes-1] = '[=11=]';

            int idTmp2;
            sem_wait(sem2);
            pid_t pidAct = getpid(); // PID OF THE NEW CREATED FORK 
            idTmp2 = *id;   // ID OF THE USER
            idTmp2--;
            strcpy(client[idTmp2].nick,userNick); 
            client[idTmp2].pidConn = pidAct;
            idTmp2 = *id;
            sem_post(sem2);
            //////////////////////////////////////////////////////////////


            // SENDS THE LIST OF CONNECTED CLIENTES
            if (send(new_fd, id, sizeof(int), 0) == -1) {
                fprintf(stderr, "Error send ID\n");
            }
            if (send(new_fd, client, sizeof(connData)*MAXCLIENT, 0) == -1) { // SEND THE WHOLE LIST
                fprintf(stderr, "Error send LIST\n");
            }
            //////////////////////////////////////////////////////////////

            // THE FORK WAITS SOME COMMAND OF THE USER
            char *comm = (char*)malloc(MAXDATASIZE);
            if( (numbytes = recv(new_fd, comm, MAXDATASIZE-1, 0)) == -1){
                fprintf(stderr,"Error rcv COMMAND\n");          
            } 
            comm[numbytes] = '[=11=]';

            // THE FORK ENTERS IN A LOOP WAITING COMMANDS
            int wait = 0;
            while(wait == 0){

                if(strcmp(comm,"clientlist") == 0){
                    if (send(new_fd, client, sizeof(connData)*MAXCLIENT, 0) == -1) {
                        fprintf(stderr, "Error send CLIENT LIST\n");
                    }

                }else if(strcmp(comm,"sendchat") == 0){
                    char *chatNick = (char *) malloc(NICKSIZE); // WAIT FOR THE CLIENT TO TALK TO
                    if(  (numbytes = recv(new_fd,chatNick, NICKSIZE, 0)) == -1){
                        fprintf(stderr,"Error server rcv CHAT NICK\n");
                    } chatNick[numbytes-1] = '[=11=]';

                    char *chatmsg = (char *)malloc(MAXMSG); // WAIT FOR MSG
                    if((numbytes = recv(new_fd, chatmsg, MAXMSG, 0)) == -1){
                        fprintf(stderr,"Error server rcv CHAT\n");
                    } chatmsg[numbytes-1] = '[=11=]';

                    int client_id;
                    sem_wait(sem2);
                    for(client_id = 0; client_id < *id; client_id++){
                        if(strcmp(client[client_id].nick, chatNick) == 0){
                            if(client[client_id].msg != NULL){
                                free(client[client_id].msg);
                            }
                            client[client_id].msg = (char * )malloc(MAXMSG); // COPY THE MESSAGE TO THE DESIRED USER
                            strcpy(client[client_id].msg, chatmsg);
                            printf("\nTHE MESSAGE TO: %s IS %s\n", client[client_id].nick, client[client_id].msg);
                        }
                    }
                    sem_post(sem2);

                    /*
                        HERE I HAVE THE NICK, SAY, 'client1' OF THE CLIENT TO WHICH I WANT TO TALK.
                        THE MSG NOW ITS IN HIS MSG BUFFER LIKE ABOVE.

                        HOW CAN I NOTICE THE FORKED PROCESS HANDLING THE CONNECTION of 'client1'
                        TO READ THE MESSAGE ?

                    */

                    free(chatmsg);
                    free(chatNick);

                }else if(strcmp(comm,"quit_") == 0){ 
                    if (send(new_fd, "Byee!!", MAXDATASIZE-1, 0) == -1) {
                        fprintf(stderr, "Error send EXIT\n");
                    }
                    wait = 1; // FOR EXIT AND CLOSE THE SOCKET

                }else{
                    if (send(new_fd, "Invalid option!", MAXDATASIZE-1, 0) == -1) {
                        fprintf(stderr, "Error send INVALID\n");
                    }
                }

                if(wait == 0){
                    // WHEN THE FORKED PROCESS HAS FULFILL THE USERS REQUEST, IT JUST WAITS FOR OTHER REQUEST
                    free(comm); comm = (char*)malloc(MAXDATASIZE);
                    if((numbytes = recv(new_fd, comm, MAXDATASIZE-1, 0)) == -1){
                        fprintf(stderr,"Error rcv REQUEST\n");          
                    } comm[numbytes] = '[=11=]';
                }   
            }
            if(munmap(client,sizeof(connData)*MAXCLIENT) != 0){ printf("ERROR FREEING MEM\n");}
            sem_unlink("sem1"); shm_unlink("shm1");
            printf("Connection ended with %d \n", new_fd);
            close(new_fd);  exit(0);
        }
        printf("Keep waiting connections.....\n");
        close(new_fd); // SOCKET DEL ACCEPT, DEL CLIENTE QUE SE HABIA CONECTADO
        //////////////////////////////////////////////////////////////////////////////
    }

    if(munmap(client,sizeof(connData)*MAXCLIENT) != 0){ printf("ERROR FREEING MEM\n");}

    sem_unlink("sem1");
    shm_unlink("shm1");

    return 0;
}

首先我要指出 fork() 和共享内存并不是创建聊天服务器的最佳或最简单的方法;如果您可以选择,我建议您以不同的方式进行操作(例如,通过单个进程中的多个线程,甚至是单个线程和 select(),而不是)。

假设您需要使用这种方法(例如,因为它是在 class 作业中规定的,或者其他),但是......您缺少的是 IPC 通知机制,即(如你说)进程 C2 注意到进程 C1 有一些数据供 C2 处理的方法。

有几种方法可以实现通知...快速而简单的方法(可能足以完成 class 分配)只是让每个进程轮询共享内存区;例如让每个进程每 100 毫秒检查一次共享内存区域的一部分,看看自上次以来是否有任何变化。在这种情况下,C1 可能会向共享内存区域写入一些新数据,然后在完成写入后在共享内存区域中增加一个整数值。下次 C2 醒来检查整数时,它会注意到整数的值与上次检查时的值不同,并认为共享内存区域中有新数据可供它处理。 (旁注:当使用共享内存时,您应该以某种方式序列化对共享内存区域的访问,否则您可能会遇到竞争条件,例如 C2 在 C1 仍在写入内存的同时开始读取内存。其症状是系统99.999% 的时间都可以正常工作,但偶尔会在时间为 "just right")

时做一些事情 weird/wrong

但是,如果您想要一种不那么骇人听闻的通知方法(即不吃 CPU 24/7 循环并且不会在每次通过服务器的行程中造成不必要的 100 毫秒延迟的方法) ,那么您需要选择一种通知机制。一种机制是使用(可以说是错误命名的)kill() 系统调用向 C2 的进程发送 UNIX 信号;然后,C2 将需要安装一个信号处理程序,使其在收到该类型的信号时执行正确的操作。

但是,如果你想避免 Unix 信号(我尽量避免它们,因为它们相当陈旧和丑陋),你将需要一种更温和的机制,通过该机制可以在以下任一情况下唤醒 C2 进程(一个 IPC收到通知)或(I/O 收到数据),以先发生的情况为准...天真的阻塞-I/O-调用机制是不够的,因为它只允许您的进程等待一件事或其他,但不是两者。获得两者的一个好方法是使用 select() 或 poll() 同时监视两个套接字:一个套接字是到客户端的 TCP 连接,另一个套接字是进程已设置的 UDP 套接字专门用于接收 IPC 通知。每个分叉进程都设置一个 UDP 套接字侦听特定端口,当 C1 想要唤醒 C2 时,C1 通过将 UDP 数据包发送到 C2 的 UDP 端口来实现。 (UDP 数据包的内容无关紧要,因为它的唯一目的是使 C2 从 select() 变为 return,并且由于 UDP 套接字已 select 准备就绪- for-read,C2 然后知道从 UDP 套接字读取数据包,丢弃数据包,然后检查共享内存区域是否有新数据。

(当然,一旦你完成了所有这些,你可能会发现 C1 更容易将 C2 的数据简单地包含在 UDP 数据包本身中,这样 C2 就不必处理潜在的共享内存地区,但这取决于您)

你快完成@Emiliano,这就是我也卡住一次的要点;)。

好吧,你有一些选项可以告诉其他进程有关消息的信息。

1.你总是寻找自己的消息缓冲区(这很糟糕,消耗很多CPU也是一个坏主意)

进程 C1 总是在 C1 的共享内存中查找它自己的内存,缓冲并检查是否有新消息,然后发送给客户端。

2。您使用信号(优于 1)

一个。客户端 C2 为 C1 发送消息。

b。进程 C2 将消息存储在共享内存上的 C1 缓冲区中。(如果我正确理解您的共享内存结构)

c。进程 C2 向 C1 发送一个信号,通知我在你的缓冲区中为你放置了一条消息。(在这种情况下,你需要知道哪个 pid 处理哪个客户端)

d。从进程获取信号后,C1 检查其缓冲区并发送到其客户端。

编辑: 看来你的信号有问题。 这是一个显示信号 sending/catching.

的简单片段

recvsig.c

static void handler(int sig, siginfo_t *si, void *data)
{
    printf("%s = %d\n", "Got a signal, signal number is ", sig);

    //you can also code here what you want, after getting a signal
}

void init_signal()
{

    struct sigaction act;

    act.sa_sigaction = handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_SIGINFO;

    sigaction(SIGRTMIN + 1, &act, NULL);

}

void main(int argc, char **argv)
{

    printf("%s %d\n", "PID", getpid());

    init_signal();

    while(1)
    {
        pause();
        {
            printf("%s\n", "Received a signal");
            //code here anything after you got signal
        }
    }

    return;
}

sendsig.c

void main(int argc, char **argv)
{

    int pid = atoi(argv[1]);


    while(1)
    {
        sleep(5);
        {
            kill(pid, SIGRTMIN+1);
            printf("%s %d\n", "Sent a signal to ", pid);
        }
    }

    return;
}

在您的程序中,在每个分叉子进程后调用 init_signal()。 确保您管理所有分叉进程 + 连接的客户端的 pid 列表。

并使用 kill() 发出正确的 pid。