实验三进程通信一.实验学时与类型学时:2,课外学时:自定实验类型:设计性实验二.实验目的了解Linux的软中断、管道、消息队列、共享存储区等进程间通信方式。
三.实验容1. 软中断通信机制(1) 请编写一个程序:循环输出“how are you?”,在按下Ctrl+C后中断显示,输出“Byebye!”后退出程序。
#include<signal.h>#include<stdio.h>int k=1;void int_func(int sig) //软中断处理函数{ k=0; }Int main(){ signal(SIGINT,int_func);//预置软中断信号处理函数While(k==1)Printf(“how are you?\n”);Printf(“byebye!”);}(2)使用信号机制实现父子进程同步,父进程先输出A,然后子进程输出B。
#include<signal.h>#include<stdio.h>int k=1;void func(int sig) { k=0; }main(){ int pid;pid=fork();if(pid>0){ printf(“A\n”);kill(pid,12);}else if(pid==0){ signal(12,func);while(k==1)sleep(1);printf(“B\n”);}}2. 管道机制(1) 父子进程通过管道传送一串字符。
要求:子进程随机从键盘输入一串字符,通过管道发给父进程,父进程从管道中将消息读出并显示出来。
#include<stdio.h>#include<unistd.h>main(){ int pid, fd[2] ;char outpipe[50], inpipe[50];pipe(fd);pid=fork();if (pid==0){Printf(“please input some message:\n”);Fgets(inpipe,sizeof(inpipe),stdin);write(fd[1],inpipe,50);}else if (pid>0);{ wait(0);Printf(“father get this message:\n”);read(fd[0],outpipe,50);printf(“%s\n”,outpipe);}}(2)父子进程通过管道互相发送字符串。
要求:子进程向父进程通过管道发送”I am child.”,父进程回送”I am father.”,父子进程将各自收到的字符串显示在屏幕上。
#inlcude<stdio.h>#include<unistd.h>#include<string.h>main(){ int pid, fd[2] ;char str1[50], str2[50];pipe(fd);pid=fork();if (pid==0){ strcpy(str1,”I’m child”);write(fd[1],str1,strlen(str1));Sleep(1);read(fd[0],str2,50);printf(“Child received: %s\n”,str2);}else if (pid>0){ read(fd[0],str1,50);printf(“Parent received:%s\n”,str1);strcpy(str2,”I’m father.”);write(fd[1],str2,strlen(str2));}}3. 消息队列机制(1) 父进程及其子进程通过一条消息队列互相传送数据。
#include<stdio.h>#include<sys/ipc.h>#include<sys/msg.h>#include<sys/types.h>int msgqid,qid;struct msg{ long mtype;char mtext[256];}pmsg;cancelqueue(){ msgctl(msgqid,IPC_RMID,0);exit(0);}main(){ int pid;Pid=fork();If (pid>0){ msgqid=msgget(75, 0777);printf(“msg id: %d\n”,msgqid);pmsg.mtype=1;*((int *)pmsg.mtext)=getpid();msgsnd(msgqid,&pmsg,sizeof(int),0);msgrcv(msgqid,&pmsg,256,getpid(),0);printf(“A:receive msg from %d\n",*((int *)pmsg.mtext)); }Else if(pid==0){ signal(2,cancelqueue);msgqid=msgget(75, 0777|IPC_CREAT);while(1){ msgrcv(msgqid,&pmsg,256,1,0);qid=*(int *)pmsg.mtext;printf(“B:receive msg from %d\n”,qid);pmsg.mtype=qid;*((int *)pmsg.mtext)=getpid();msgsnd(msgqid,&pmsg,sizeof(int),0);}}}(2) 非父子进程之间实通过一条消息队列互相传递数据。
A进程:#include<stdio.h>#include<sys/ipc.h>#include<sys/msg.h>#include<sys/types.h>struct msg{ long mtype;char mtext[256];}pmsg;main(){ int msgqid,pid;msgqid=msgget(75, 0777);printf(“msg id: %d\n”,msgqid);pmsg.mtype=1;*((int *)pmsg.mtext)=getpid();msgsnd(msgqid,&pmsg,sizeof(int),0);msgrcv(msgqid,&pmsg,256,getpid(),0);printf(“A:receive msg from %d\n”,*((int *)pmsg.mtext)); }B进程:#include<stdio.h>#include<sys/ipc.h>#include<sys/msg.h>#include<sys/types.h>int msgqid,pid;struct msg{ long mtype;char mtext[256];}pmsg;cancelqueue(){ msgctl(msgqid,IPC_RMID,0);exit(0);}main(){ signal(2,cancelqueue);msgqid=msgget(75, 0777|IPC_CREAT);while(1){ msgrcv(msgqid,&pmsg,256,1,0);pid=*(int *)pmsg.mtext;printf(“B:receive msg from %d\n”,pid);pmsg.mtype=pid;*((int *)pmsg.mtext)=getpid();msgsnd(msgqid,&pmsg,sizeof(int),0);}}4. 共享存机制(1) 编程实现基于共享存的进程间通信。
要求:进程A通过共享存将自己的进程号传递给进程B。
A:#include<stdio.h>#include<sys/shm.h>main(){ int shmid;int *va;shmid=shmget(22,sizeof(*va),0666|IPC_CREAT);va=(int *)shmat(shmid, 0,0);*va=getpid();printf(“get A’s pid:%d\n”,*va);shmdt(va);}B:#include<stdio.h>#include<sys/shm.h>main(){ int shmid;int *va;shmid=shmget(22,sizeof(*va),0666|IPC_CREAT);va=(int*)shmat(shmid, 0,0);printf(“A’s pid is :%d\n”,*va);shmdt(va);shmctl(shmid,IPC_RMID,0);}(2) 若要通过共享存实现进程A与进程B互送进程号,可怎样编程实现?A:#include<stdio.h>#include<sys/shm.h>main(){ int shmid;int *va;shmid=shmget(22,sizeof(*va),0666|IPC_CREAT);va=(int *)shmat(shmid, 0,0);*va=getpid();printf(“get A’s pid:%d\n”,*va);Sleep(2);printf(“B’s pid is:%d\n”,*va)shmdt(va)}B:#include<stdio.h>#include<sys/shm.h>main(){ int shmid;int *va;shmid=shmget(22,sizeof(*va),0666|IPC_CREAT);va=(int*)shmat(shmid, 0,0);printf(“A’s pid is :%s\n”,*va);*va=getpid();printf(“get B’s pid:%d\n”,*va);shmdt(va);shmctl(shmid,IPC_RMID,0);}5. SOCKET进程通信(选做)编程实现基于SOCKET的进程间通信,通过网络实现进程之间数据通信。
要求:分别编写服务器端和客户端方程序,运行于不同终端,二者可相互进行通信。
Server:#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>int main(){int server_sockfd = -1;int client_sockfd = -1;int client_len = 0;struct sockaddr_in server_addr;struct sockaddr_in client_addr;//创建流套接字server_sockfd = socket(AF_INET, SOCK_STREAM, 0);//设置服务器接收的连接地址和监听的端口server_addr.sin_family = AF_INET;//指定网络套接字server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//接受所有IP地址的连接server_addr.sin_port = htons(9736);//绑定到9736端口//绑定(命名)套接字bind(server_sockfd,(struct sockaddr*)&server_addr, sizeof(server_addr));//创建套接字队列,监听套接字listen(server_sockfd, 5);//忽略子进程停止或退出信号signal(SIGCHLD, SIG_IGN);while(1){char ch = '\0';client_len = sizeof(client_addr);printf("Server waiting\n"); //接受连接,创建新的套接字client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_addr, &client_len);if(fork() == 0){//子进程中,读取客户端发过来的信息,处理信息,再发送给客户端read(client_sockfd, &ch, 1);sleep(5);ch++;write(client_sockfd, &ch, 1);close(client_sockfd);exit(0);}else{//父进程中,关闭套接字close(client_sockfd);}}}Client:#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <stdlib.h>int main(){int sockfd = -1;int len = 0;struct sockaddr_in address;int result;char ch = 'A'; //创建流套接字sockfd = socket(AF_INET, SOCK_STREAM, 0); //设置要连接的服务器的信息address.sin_family = AF_INET;//使用网络套接字address.sin_addr.s_addr = inet_addr("127.0.0.1");//服务器地址address.sin_port = htons(9736);//服务器所监听的端口len = sizeof(address);//连接到服务器result = connect(sockfd, (struct sockaddr*)&address, len);if(result == -1){perror("ops:client\n");exit(1);}//发送请求给服务器write(sockfd, &ch, 1);//从服务器获取数据read(sockfd, &ch, 1);printf("char form server = %c\n", ch);close(sockfd);exit(0);}四.思考与总结(1) 请对比下列程序与实验1(1)在按下Ctrl+C之后的运行现象。