【linux下c语言服务器开发系列3】进程间通讯

给你一囗甜甜゛ 提交于 2019-12-01 16:24:20

    上个博文说道,信号是在进程间通讯的的一种方式。例如子进程执行结束后,向父进程发送sigchld信号,父进程就通过捕获这个信号,就可以对子进程的资源进行回收,避免其成为僵尸进程。

    进程间通信的另外一种方式是管道,主要是在父子进程间。父进程通过创立一个管道,fork()出子进程后,子进程继承父进程的管道,从而,父子进程就形成了管道的两端,从而可以靠这两端,进行父子进程之间的通信。

创建管道

    创建管道的方法主要有两种,一种是pipe函数,可以man一下,解释很清晰的;另外一种是socketpair函数。前者创建的管道是半双工的,后者的是全双工的。

    下面是一个父子进程间通讯的一个小例子。连接见http://git.oschina.net/mengqingxi89/codelittle/blob/master/codes/echoserver/ipc_shared_talker.cpp

例子中有个小问题没有解决,就是父进程往管道里写数据,如果写的过快的话,导致子进程没有接到。所以我让父进程写一句,sleep(1),然后再写。这样,子进程就都收到了。我想,可能是管道没有存储的功能?多写的话,就写不进去了。不知道。

进程间通讯的另一个方式是共享内存。这个,我要在下面的聊天室程序里介绍,这里就没介绍了。

#include"head.h"
#define MAX_USER 1024
#define MAX_PROCESS 65535
#define BUF_SIZE 1024 

typedef struct user
{
        int conn;
        int stop;
        sockaddr_in client_addr;
        char bufread[BUF_SIZE];
        char bufwrite[BUF_SIZE];
        int pipefd[2];   //用来建立管道,一端是父进程,一端是子进程。
} user;


typedef struct subprocessData
{
        user* u;
        pid_t pid;
        pid_t ppid;

}subprocessData;


subprocessData subprocess[MAX_PROCESS];


/*子进程从父进程那里读取内容*/
int dowork_comm_with_father(user curuser)
{       

        curuser.stop=0;
        //子进程关闭写端
        close(curuser.pipefd[1]);

        setnonblock(curuser.pipefd[0]);
        while(!curuser.stop )
        {

            int readn=read(curuser.pipefd[0],curuser.bufread,BUF_SIZE);
            if( (readn<0) && (errno!=EAGAIN))
            {
                    printf("a\n");
                    printf("read fail, client ");
                    close(curuser.pipefd[0]);
                    curuser.stop=1;
                    
            }
            else if (readn==0)
            {
                    printf("father close the pipe\n");
                    close(curuser.pipefd[0]);
                    curuser.stop=1;
            }

            else if (readn>0)
            {
                    printf("pid= %d\n",getpid());
                    curuser.bufread[readn]='\0';
                    printf("read from the father\n");
                    printf("%s\n",curuser.bufread);
                    int writen=write(1,curuser.bufwrite,sizeof(curuser.bufwrite));
                    
                    memset(curuser.bufread,0,sizeof(curuser.bufread));
            }


        }
}
        int main(int argc, char **argv)
        {
                printf("start server...\n");


        /*服务器服务启动,等待客户端的链接的到来*/
            int run_flag=1;

            user users[MAX_USER];
            int user_number=0;
            /*这个pipe函数是简单的创建管道的版本,他创建的管道,pipefd[0]只能读,pipefd[1]只能写*/
            int fdret=pipe(users[user_number].pipefd);
            
            assert(fdret>=0);

            pid_t pid=fork();
            if(pid<0)
            {
                    printf("fork error\n");
                    exit(0);
            }
            else if (pid==0)
            {

                    dowork_comm_with_father(users[user_number]);
            }

            /*parent process*/
            else
            {
                    /*在父进程中向子进程写一些random内容*/

                    printf("pid=%d in parent\n",pid);
                    subprocess[pid].u=&users[user_number];
                    close(users[user_number].conn);
                    //父进程关闭管道的读端,只往子进程写内容
                    close(users[user_number].pipefd[0]);

                    int write_times=5;
                    for(int i=0;i<write_times;i++)
                    {
                            
                            char buf[100]="hello from parent at time ";
                            char bufwrite[100];
                            sprintf(bufwrite,"%s",buf);
                            sprintf(bufwrite," %d\n",time(NULL));
                            write(users[user_number].pipefd[1],bufwrite,sizeof(bufwrite));

                            sleep(1);
                    }
                    printf("parent write over\n");

                    int stat_loc;
                    /*如果想要多个进程共同服务的话,就不能在这里阻塞的等待,可以通过sigchld信号进行捕获,见信号handler*/
                 //   wait((int *)&stat_loc);
                    printf("parent, finished wait\n");
                   // sleep(3);
            }

        
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!