实验三 Linux进程间通信

时间:2024.5.15

实验三 Linux进程间通信

一、实验目的

熟悉Linux下进程间通信机制,能够使用系统提供的各种通信机制实现并发进程间的数据交换。

二、实验题目

分别使用Linux下的共享存储区、消息、管道等通信机制,编程实现并发进程之间的相互通信。

三、背景材料

(一)需要用到的系统调用

实验可能需要用到的主要系统调用和库函数在下面列出,详细的使用方法说明通过“man 2 系统调用名”或者“man 3 函数名”命令获取。

fork() 创建一个子进程,通过返回值区分是在父进程还是子进程中执行; wait() 等待子进程执行完成;

getpid() 获取当前进程id;

shmget() 建立一个共享存储区;

shmctl() 操纵一个共享存储区;

shmat() 把一个共享存储区附接到进程内存空间;

shmdt() 把一个已经附接的共享存储区从进程内存空间断开; msgget() 建立一个消息队列;

msgctl() 操纵一个消息队列;

msgsnd() 发送消息;

msgrcv() 接收消息;

signal() 设置对信号的处理方式或处理过程;

pipe() 打开管道;

lockf() 锁定一个文件。

(二)使用共享存储区的示例程序

下面程序主要用来演示共享存储区的使用方法:首先要使用shmget得到共享存储区句柄(可以新建或连接已有的共享存储区,以关键字标识),然后使用shmat挂接到进程的存储空间(这样才能够访问),当使用完后,使用shmctl释放(shmctl还可以完成一些其他功能)。这种使用逻辑也适用于消息和信号量。示例程序代码如下:

#include <sys/types.h>

#include <unistd.h>

#include <stdio.h>

#include <sys/ipc.h>

#include <sys/shm.h>

int main(void)

{

int x, shmid;

int *shmptr;

if((shmid=shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT|0666)) < 0)

printf("shmget error"), exit(1); if((shmptr=(int *)shmat(shmid, 0, 0)) == (int *)-1)

printf("shmat error"), exit(1);

printf("Input a initial value for *shmptr: ");

scanf("%d", shmptr);

while((x=fork())==-1);

if(x==0) /* child run */

{

printf("When child runs, *shmptr=%d\n", *shmptr);

printf("Input a value in child: ");

scanf("%d", shmptr);

printf("*shmptr=%d\n", *shmptr);

}

else /* parent run */

{

wait();

printf("After child runs, in parent, *shmptr=%d\n", *shmptr);

if ( shmctl(shmid, IPC_RMID, 0) < 0 )

printf("shmctl error"), exit(1);

}

}

(三)使用消息机制的示例程序

示例程序执行的进程分为两种,分别称为服务进程和客户进程:服务进程只有一个,接收各客户进程以消息形式发出的问题,接收键盘输入作为回答,再以消息形式送给提问的进程。各客户进程接收键盘输入作为问题,以消息形式发给服务进程,等待接收服务进程发来的回答消息,再开始下一轮的循环。示例程序的实际执行效果如下:

编译后执行,第一个进程实例将作为服务进程,提示:

ACT SERVER!!! Wait question and give answer.

To end this process, try Ctrl+C or use kill.

服务进程一直循环执行,直到用户按Ctrl+C终止执行,或使用kill命令杀死服务进程。 其他进程实例作为客户进程,提示:

Act as client, ask question and wait answer!

To end this process, enter end as input question.

客户进程一直循环执行,直到用户输入end。

示例程序的代码如下:

#include <sys/types.h>

#include <unistd.h>

#include <signal.h>

#include <stdio.h>

#include <string.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#define MY_KEY 10071140 // need to change

#define SERVER_ID 2

#define MAX_BUF 200

void sigend(int);

struct mymsg {

long mtype;

long pid;

char buf[MAX_BUF];

};

int msgid;

int main(void)

{

struct mymsg msgbuf;

if((msgid=msgget(MY_KEY, IPC_CREAT|IPC_EXCL|0666)) < 0 ) { /* message queue exists, act as client */

msgid=msgget(MY_KEY, 0666);

printf("Act as client, ask question and wait answer!\n");

printf("To end this process, enter end as input question.\n\n"); printf("Input question in one line:\n");

fgets(msgbuf.buf, sizeof(struct mymsg)-2*sizeof(long)-1, stdin); while(strcmp(msgbuf.buf,"end\n"))

{

msgbuf.mtype=SERVER_ID;

msgbuf.pid=getpid();

msgsnd(msgid, &msgbuf, sizeof(struct mymsg)-sizeof(long), 0); msgrcv(msgid, &msgbuf, sizeof(struct mymsg), getpid(), 0); printf("Answer from server: \n%s", msgbuf.buf);

printf("Input question in one line:\n");

fgets(msgbuf.buf, sizeof(struct mymsg)-2*sizeof(long)-1, stdin); }

}

else /* acts as server */

{

signal(SIGINT, sigend);

signal(SIGTERM, sigend);

printf("ACT SERVER!!! Wait question and give answer.\n"); printf("To end this process, try Ctrl+C or use kill.\n\n");

while(1)

{

msgrcv(msgid, &msgbuf, sizeof(struct mymsg), SERVER_ID, 0); printf("Question from %d: \n%sGive answer:\n", (int)msgbuf.pid, msgbuf.buf);

fgets(msgbuf.buf, sizeof(struct mymsg)-2*sizeof(long)-1, stdin);

msgbuf.mtype=msgbuf.pid;

msgsnd(msgid, &msgbuf, sizeof(struct mymsg)-sizeof(long), 0);

}

}

}

void sigend(int sig)

{

msgctl(msgid, IPC_RMID, 0);

exit(0);

}

(四)使用管道机制的示例程序

以下示例程序摘自pipe系统调用的man手册页,因一些Linux发行版相应man手册页丢失,故摘录如下:

#include <sys/wait.h>

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

int main(int argc, char *argv[])

{

int pipefd[2];

pid_t cpid;

char buf;

if (argc != 2) {

fprintf(stderr, "Usage: %s <string>\n", argv[0]);

exit(EXIT_FAILURE);

}

if (pipe(pipefd) == -1) {

perror("pipe");

exit(EXIT_FAILURE);

}

cpid = fork();

if (cpid == -1) {

perror("fork");

exit(EXIT_FAILURE);

}

if (cpid == 0) { /* Child reads from pipe */

close(pipefd[1]); /* Close unused write end */

while (read(pipefd[0], &buf, 1) > 0)

write(STDOUT_FILENO, &buf, 1);

write(STDOUT_FILENO, "\n", 1);

close(pipefd[0]);

_exit(EXIT_SUCCESS);

} else { /* Parent writes argv[1] to pipe */

close(pipefd[0]); /* Close unused read end */

write(pipefd[1], argv[1], strlen(argv[1]));

close(pipefd[1]); /* Reader will see EOF */

wait(NULL); /* Wait for child */

exit(EXIT_SUCCESS);

}

}

四、实验内容

本实验要求内容如下:

1、使用消息机制进行进程通信

实现使用消息机制的示例程序功能,改造该程序的结构,使服务器进程和客户进程执行不同的程序;服务器程序的多次执行应报错退出(保证服务器进程唯一)。

2、使用共享存储区进行通信

使用共享存储区作为通信机制,实现如下通信功能:服务进程和客户进程通过共享存储区交换一个整数;服务进程首先等待客户进程改变共享存储区的数值,显示该数值后接收键盘输入整数,修改共享存储区内容。客户进程接收键盘输入整数(如果输入0则退出),修改共享存储区内容,然后等待服务进程改变整数值后,再开始下一轮的循环。

3、使用管道进行通信

编写程序建立一个无名管道,然后生成3个子进程,使这4个进程利用同一个管道进行通信。分别试验3写1读、2写2读情况,对记录的执行结果进行解释。

五、实验报告书写要求

应在实验报告中说明如下事项:

1、相关程序的名称及存储位置,以便指导教师抽查;

2、实验内容1中自己修改部分的描述,执行结果的描述和分析;

3、实验内容2的执行结果描述及分析;

4、实验内容3的功能设计描述,执行结果的描述和分析。


第二篇:实验五 Linux进程间通信05010501


实验五 Linux进程间通信

【实验目的】

掌握管道通信程序的基本编写方法

掌握信号通信程序的基本编写方法

掌握信号量通信程序的编写方法

掌握共享内存通信程序的编写方法

掌握消息队列通信程序的编写方法

【实验学时】

建议2学时

【实验内容】

1、了解什么是管道,熟悉LINUX支持的管道通信方式

2、了解什么是信号,熟悉LINUX系统中进程之间软中断通信的基本原理。

【实验原理】

见教材第四章

【实验要求】

调试验证程序,并提交实验报告。

【实验步骤】

(1) 打开目录4-1-0-ipc,将其中的produce-core-dump.c文件编译生成可执行文件。输入:Ulimit –c 1024命令,使程序出错后可生成core dump文件,运行produce-core-dump的可执行文件,观察结果。

(2) 打开目录4-2-1-ipc-pipe和4-2-2-ipc-standard-pipe,编译并运行后,观察运行结果。打开目录4-2-3-ipc-fifo-pipe,在PC机Fedora中编译并运行后,观察运行结果。将程序交叉编译后,在开发板的控制终端与PC机Fedora的控制终端中分别运行读写管道程序,观察运行结果。

(3) 打开目录4-3-1-ipc-kill-raise、4-3-2-ipc-alarm-pause、4-3-3-1-ipc-signal、4-3-3-2-ipc-signalaction和4-3-3-3-ipc-signaleset,编译并运行程序,观察运行结果。

(4) 打开目录4-4-ipc-sem编译并运行程序,观察运行结果。

(5) 打开目录4-5-ipc-shmem编译并运行程序,观察运行结果。

(6) 打开目录4-6-ipc-msg编译并运行程序,观察运行结果。

(7) 打开目录4-7-1-ipc编译并运行程序,观察运行结果。

(8) 打开目录4-7-2-ipc编译并运行程序,观察运行结果。

(9) 将上面程序交叉编译后,在开发板上运行,观察运行结果。

【思考题】

思考题1. 管道通信

编制一段程序,实现进程的管道通信。使用pipe()建立一条管道线。两个子进程p1和p2分别向管道各写一句话:

Child 1 is sending message!

Child 2 is sending message!

而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。

<参考程序>

# include<unistd.h>

# include<signal.h>

# include<stdio.h>

int pid1,pid2;

main()

{

int fd[2];

char OutPipe[100],InPipe[100];

pipe(fd);

while((pid1=fork())== -1);

if(pid1 == 0)

{

lockf(fd[1],1,0);

sprintf(OutPipe, "child 1 process is sending message!");

write(fd[1],OutPipe,50);

sleep(5);

lockf(fd[1],0,0);

exit(0);

}

else{

while((pid2=fork())== -1);

if(pid2 == 0)

{

lockf(fd[1],1,0);

sprintf(OutPipe, "child 2 process is sending message!");

write(fd[1],OutPipe,50);

sleep(5);

lockf(fd[1],0,0);

exit(0);

}

else{

wait(0);

read(fd[0],InPipe,50);

printf("%s\n",InPipe);

wait(0);

read(fd[0],InPipe,50);

printf("%s\n",InPipe);

exit(0);

}

}

}

实验要求:运行程序并分析结果,将上面程序修改成,在父进程中用pipe()建立一条管道,往管道里写字符串,两个子进程分别接收父进程往管道里写的字符串。

思考题2. 使用信号在进程中通信

编写一段程序,使用系统调用fork( )创建两个子进程,再用系统调用signal( )让父进 程捕捉键盘上来的中断信号(即按ctrl+c键),当捕捉到中断信号后,父进程用系统调用kill( )向两个子进程发出信号,子进程捕捉到信号后,分别输出下列信息后终止:

Child process 1 is killed by parent!

Child process 2 is killed by parent!

父进程等待两个子进程终止后,输出以下信息后终止:

Parent process is killed!

<参考程序>

/***********************************************************

功能说明:进程通信singnal()方法的应用

author: lilan

***********************************************************/

#include<stdio.h>

#include<signal.h>

#include<unistd.h>

#include<sys/types.h>

#include<sys/wait.h>

int wait_mark = 0;

void waiting(),stop();

int main(){

int p1, p2;

signal(SIGINT,stop);//捕捉到中断信号ctrl-c后,调用stop函数

while((p1=fork())== -1);

//int status1 = -1;

//int status2 = -1;

if(p1>0){/*在父进程中*/

//signal(SIGINT,stop);//①

while( (p2=fork()) == -1 );

if( p2>0 ){/*在父进程中*/

//signal(SIGINT,stop);//②

wait_mark=1;

waiting();

kill(p1,10);

kill(p2,12);

wait(0);//父进程执行到此,马上阻塞自己,直到有子进程结束。当发现有子进程结束时,就会回收它的资源。

wait(0);

//wait(&status1);

//wait(&status2);

//printf("child1 exit status is %d\n", WEXITSTATUS(status1)); //printf("child2 exit status is %d\n", WEXITSTATUS(status2)); printf("parent process is killed!\n");

exit(0);

}

else{ /*在子进程2中*/

wait_mark=1;

signal(12,stop); //捕捉到中断信号12后,调用stop函数

waiting();

lockf(1,1,0);

//printf("this is child 2, pid = %d , ppid = %d\n",getpid(),getppid() );

printf("child process 2 is killed by parent!\n");

lockf(1,0,0);

exit(0);

//exit(5);

}// end of if (p2>0)

}

else{ /*在子进程1中*/

wait_mark=1;

signal(10,stop);//捕捉到中断信号10后,调用stop函数

waiting();

lockf(1,1,0);

//printf("this is child 1, pid = %d , ppid = %d\n",getpid(),getppid() ); printf("child process 1 is killed by parent!\n");

lockf(1,0,0);

exit(0);

//exit(6);

}// end of if ( p1>0 )

exit(0);

}

void waiting(){

while(wait_mark!=0);

}

void stop(){

wait_mark=0;

}

(1)运行程序并分析结果。

(2)如果把signal(SIGINT,stop)放在①号和②号位置,结果会怎样并分析原因。

(3)该程序段前面部分用了两个wait(0),为什么?

(4)该程序段中每个进程退出时都用了语句exit(0),为什么?

(5)将红色部分去掉注释,蓝色部分加上注释,观察程序运行结果,并分析原因,进一步理解wait函数的使用!

更多相关推荐:
Linux下查看端口占用进程号,程序名的方法

Linux下查看端口占用进程号程序名的方法Linux下查看端口占用进程号程序名的方法方便我们查找什么进程导致系统变慢等需要linux下查看端口占用情况1查看哪个进程占用了819端口case9sghfofousr...

linux 监听并杀死端口命令

Linux下ps查找进程用kill终止命令监听端口命令lsofi8080使用linux操作系统难免遇到一些软件quot卡壳quot的问题这时就需要使用linux下强大的kill命令来结束相关进程这在linux系...

Linux查看服务器端口被哪个程序占用

Linux查看服务器端口被哪个程序占用我们经常会遇到网站打不开参看服务器运行状态会发现apachemysql的端口被其他应用程序占用导致程序无法启动的情况那么如何查看linux端口号被占用的是哪一个程序呢可以通...

linux端口修改

SUSELinux立即关闭防火墙的命令和指定开放某些端口SUSE防火墙查看命令linuxchkconfiglistgrepifireSuSEfirewall2init0off1off2off3off4off5o...

linux下查看进程的完整路径

linux下查看进程的完整路径当我们查看系统正在运行的进程时有时候我们想查看以下进程的详细信息包括绝对路径这个时候ps的不足指出就显露出来了而强大的top也只能查看到进程名而已这个时候怎么办呢个人理解在linu...

linux查看端口的方法

想查看TCP或者UDP端口使用情况使用netstatanp如果有些进程看不见如只显示可以尝试sudonetstatanp如果想看某个端口的信息使用lsof命令如sudolsofi631bash300netsta...

linux查看端口的方法

想查看TCP或者UDP端口使用情况使用netstatanp如果有些进程看不见如只显示可以尝试sudonetstatanp如果想看某个端口的信息使用lsof命令如sudolsofi631bash300netsta...

一个linux的端口读写程序

一个linux的端口读写程序本程序符合GPL条约MyComcincludeltstdiohgtprintfincludeltfcntlhgtopenincludeltstringhgtbzeroincludel...

Linux网络编程之绑定端口注意事项及端口复用

Linux网络编程之绑定端口注意事项及端口复用所谓绑定bind是指别人连接我只能通过我所绑定的端口相当于我买了一个手机别人要想联系我必须要知道我的手机号码这时候我需要怎么办呢我需要给手机插上电话卡固定一个电话号...

Linux中如何查看服务及监听端口

linux教程实例Linux中如何查看服务及监听端口问我该如何发现哪种服务正在某个特定端口上监听呢我如何发现哪一个程序正在一个特定端口上监听呢答在NIX系统中你可以使用下面的任何一个命令来得到在一个特定TCP端...

佛山双线服务器Linux下查看端口占用进程号

佛山双线服务器Linux下查看端口占用进程号程序名的方法佛山双线服务器Linux下查看端口占用进程号程序名的方法方便我们查找什么进程导致系统变慢等需要东莞市博扬网络技术有限公司总结linux下查看端口占用情况1...

linux开启防火墙端口和查看,开启相关端口号

当Linux打开防火墙后你会发现从本机登录23端口是没有问题的但是如果从另一台pc登录该linux系统后你会发现提示这样的错误不能打开到主机的连接在端口23连接失败因为linux防火墙默认是关闭23端口的如果允...

linux 端口号 进程(11篇)