《TCP IP网络编程》第十一章 进程间通信

第十一章 进程间通信

管道PIPE

#include<unistd.h>
int pipe(int filedes[2]);
	filedes[0] 	通过管道接收数据时使用的文件描述符,管道出口
	filedes[1]  通过管道传输数据时使用的文件描述符,管道入口
成功返0,失败返-1

通过一个管道进行数据交互:
数据进入管道后成为无主数据,谁先调用read谁先获取数据,故将数据写入管道后要sleep一段时间再read。
sleep(3);睡眠3秒是为了显示时格式不错乱。

[root@VM_0_10_centos communication]# cat pipe2.c
#include<stdio.h>
#include<unistd.h>
#define BUF_SIZE 30

int main(int argc,char * argv[]){
        int fds[2];
        char str1[] = "who are you?";
        char str2[] = "Thank you for your message.";
        char buf[BUF_SIZE];
        pid_t pid;

        pipe(fds);
        pid = fork();
        if(pid == 0){
                write(fds[1],str1,sizeof(str1));
                sleep(2);//非常重要
                read(fds[0],buf,BUF_SIZE);
                printf("Child proc output:%s\n",buf);
        }else{
                read(fds[0],buf,BUF_SIZE);
                printf("Parent proc output:%s\n",buf);
                write(fds[1],str2,sizeof(str2));
                sleep(3);
        }
        return 0;
}

双向通信的正确打开方式:使用两个管道:

#include<stdio.h>
#include<unistd.h>
#define BUF_SIZE 30

int main(int argc,char * argv[]){
        int fds1[2],fds2[2];
        char str1[] = "who are you?";
        char str2[] = "Thank you for your message.";
        char buf[BUF_SIZE];
        pid_t pid;

        pipe(fds1),pipe(fds2);
        pid = fork();
        if(pid == 0){
                write(fds1[1],str1,sizeof(str1));
                read(fds2[0],buf,BUF_SIZE);
                printf("Child proc output:%s\n",buf);
        }else{
                read(fds1[0],buf,BUF_SIZE);
                printf("Parent proc output:%s\n",buf);
                write(fds2[1],str2,sizeof(str2));
                sleep(3);
        }
        return 0;
}

更完备的回声服务器端:
能够保存客户端发来的数据到指定的文件中。累积到10条内容后就不再保存了。
将保存任务委托给另外的进程:另行创建进程,从向客户端提供服务的进程读取字符串信息。

[root@VM_0_10_centos communication]# cat echo_storeserv.c 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
#include<arpa/inet.h>
#include<sys/socket.h>

#define BUF_SIZE 30
void error_handling(char * message);
void read_childproc(int sig);

int main(int argc,char* argv[]){
        int serv_sock,clnt_sock;
        struct sockaddr_in serv_adr,clnt_adr;
        int fds[2];

        pid_t pid;
        struct sigaction act;
        socklen_t adr_sz;
        int str_len,state;
        char buf[BUF_SIZE];
        if(argc != 2){
                printf("Usage:%s <port> \n",argv[0]);
                exit(1);
        }

        act.sa_handler = read_childproc;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        state = sigaction(SIGCHLD, &act, 0);

        serv_sock = socket(PF_INET,SOCK_STREAM,0);
        memset(&serv_adr,0,sizeof(serv_adr));
        serv_adr.sin_family = AF_INET;
        serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
        serv_adr.sin_port = htons(atoi(argv[1]));

        if(bind(serv_sock,(struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1){
                error_handling("bind() error");
        }
        if(listen(serv_sock,5)==-1){
                error_handling("listen() error");
        }

        pipe(fds);
        pid = fork();
        if(pid == 0){
                FILE * fp = fopen("echomsg.txt","wt");
                char msgbuf[BUF_SIZE];
                int i,len;

                for(i = 0;i<10;++i){
                        len = read(fds[0],msgbuf,BUF_SIZE);
                        fwrite((void*)msgbuf, 1, len, fp);
                }
                fclose(fp);
                return 0;
        }

        while(1){
                adr_sz = sizeof(clnt_adr);
                clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);
                if(clnt_sock == -1){
                        continue;
                }else{
                        puts("new client connected...");
                }

                pid = fork();
                if(pid == -1){
                        close(clnt_sock);
                        continue;
                }
                if(pid == 0){
                        close(serv_sock);
                        while((str_len = read(clnt_sock,buf,BUF_SIZE)) != 0){
                                write(clnt_sock, buf, str_len);
                                write(fds[1],buf,str_len);
                        }
                        close(clnt_sock);
                        puts("client disconnected...");
                        return 0;
                }else{
                        close(clnt_sock);
                }
        }
        close(serv_sock);
        return 0;

}

void read_childproc(int sig){
        pid_t pid;
        int status;
        pid = waitpid(-1,&status,WNOHANG);
        printf("remove proc id: %d \n",pid);
}

void error_handling(char * message){
        fputs(message,stderr);
        fputc('\n',stderr);
        exit(1);
}

不要只图快,充满功利主义。即使开始时只想学习必要部分,最后也会需要掌握所有内容。

课后习题:
1、什么是进程间通信?分别从概念和内存的角度进行说明

概括性地说,进程间通信是指两个进程之间交换数据。但是从内存的角度看,可以理解为两个进程共有内存。因为共享的内存区域存在,可以进行数据交换

2、进程间通信需要特殊的IPC机制,这是由操作系统提供的。进程间通信时为何需要操作系统的帮助?

要想实现IPC机制,需要共享的内存,但由于两个进程之间不共享内存,因此需要操作系统的帮助,也就是说,两进程共享的内存空间必须由操作系统来提供

3、“管道”是典型的IPC技术。关于管道,请回答如下问题。

(1)管道是进程间交换数据的路径。如何创建该路径?由谁创建?

管道是由pipe函数产生的,而实际产生管道的主体是操作系统

(2)为了完成进程间通信,2个进程需同时连接管道。那2个进程如何连接到同一管道?

pipe函数通过输入参数返回管道的输入输出文件描述符。这个文件描述符在fork函数中复制到了其子进程,因此,父进程和子进程可以同时访问同一管道。

(3)管道允许进行2个进程间的双向通信。双向通信中需要注意哪些内容?

管道并不管理进程间的数据通信。因此,如果数据流入管道,任何进程都可以读取数据。因此,要合理安排共享空间的输入和读取

4、编写示例复习IPC技术,使2个进程相互交换3次字符串…

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#define BUF_SIZE 30

int main(){
        pid_t pid;
        int i;
        int fds1[2],fds2[2];
        char* s1 = "hello1";
        char* s2 = "hello2";
        char* s3 = "hello3";
        char* strs[] = {s1,s2,s3};

        char buf[BUF_SIZE];

        pipe(fds1),pipe(fds2);
        pid = fork();
        if(pid == 0){
                for(i=0;i<3;++i){
                        write(fds1[1],strs[i],strlen(strs[i])+1);
                        read(fds2[0],buf,BUF_SIZE);
                        printf("child proc:%s\n",buf);
                }
        }else{
                for(i=0;i<3;++i){
                        read(fds1[0],buf,BUF_SIZE);
                        printf("parent proc:%s\n",buf);
                        write(fds2[1],strs[i],strlen(strs[i])+1);
                        sleep(1);//是为了避免最后一条输出打印在了[root@VM_0_10_centos communication]# 后面
                }

        }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值