【问题标题】:ChatRoom Service between Clients in C - TCPC 中客户端之间的聊天室服务 - TCP
【发布时间】:2015-10-05 08:42:05
【问题描述】:

开始吧,我想做的是一个多客户端聊天服务。 我已经阅读了数千篇与之相关的帖子,但其中大部分都是用线程实现的,没有任何帮助,我需要使用 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 注意到对我来说是一条新消息。

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

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

注意: 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] = '\0'; 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] = '\0';
                }

                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] = '\0';
                }

                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] = '\0'; 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] = '\0';

            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] = '\0';

            // 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] = '\0';

                    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] = '\0';

                    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] = '\0';
                }   
            }
            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;
}

【问题讨论】:

    标签: c linux fork chat ipc


    【解决方案1】:

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

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

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

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

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

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

    【讨论】:

    • 很好的解释和细节。一旦我尝试过第一种和第二种方法。在阅读了您的第三种方法 UDP 方法后,我认为这将是最简单的,而不必从各个方面管理共享内存。我错过了,但我今天学到了一种新方法。谢谢。
    • 但是,如果正如您在我的代码中看到的那样,如果分叉的进程被阻止等待用户的命令,我该如何进行轮询?如果我的问题很愚蠢,我很抱歉,但我找不到最终完成这项任务的方法
    • @Emiliano 实际上,您不需要在当前代码中使用poll()select()。因为使用select()是单进程服务器。
    • Emiliano 要进行民意调查,您必须有办法强制您的进程每隔一段时间唤醒一次。一种方法是将您的套接字设置为非阻塞模式(通过 setsockopt),以便 io 调用永远不会阻塞;然后为了防止 CPU 旋转,使用指定超时参数的 select() 阻塞一段时间,或者只是调用 usleep() 代替。或者,如果您想使用阻塞 io,您可以设置 SO_TIMEOUT 或安装 SIGALRM 以定期关闭这些调用。
    【解决方案2】:

    @Emiliano 你快完成了,这就是我曾经被卡住的地方;)。

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

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

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

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

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

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

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

    d。在从一个进程获得信号后,C1 检查它的缓冲区并发送给它的客户端。

    编辑: 看来你的信号有问题。 这是一个简单的 sn-p 显示信号发送/捕获。

    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 信号。

    【讨论】:

    • 没错,我的共享结构中包含所有信息:nick、ip、端口、时间戳、handlerPID,但我已经尝试使用 kill(handlerPID, SIGINT) 发送并捕获信号只要数据可用但它不起作用,我就无法正确捕捉到信号。
    • 嗯,你应该知道你在发送什么信号。我看到SIGINT。该信号的默认动作是终止程序。您应该使用SIGRTMIN+n,其中 n 为 1,2,3,....uptomax。
    • 所以,如果我理解正确,每次我 fork 一个新的子进程并且当有新数据时,我都会使用 kill() 与相应的子进程一起使用 init_signal() 安装信号身份证。
    • 安装信号后,我的代码出现了非常奇怪的行为。 @pmverma 我做得对吗?
    • 问题是在安装信号时,act.sa_flags = SA_SIGINFO; 需要另一个标志; SA_RESTART 这样进程从信号处理程序返回后可以返回到原始状态。这导致我的进程......说“丢失”并且从未从其信号状态返回。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-04
    • 1970-01-01
    • 2018-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多