您好,欢迎来到抵帆知识网。
搜索
您的当前位置:首页实验五进程间通信

实验五进程间通信

来源:抵帆知识网
实验五 进程间通信

UNIX/LINUX系统的进程间通信机构(IPC)允许在任意进程间大批量地交换数据。本实验的目的是了解和熟悉LINUX支持的信号机制、管道机制、消息队列通信机制及共享存储区机制。

5.1信号机制实验(一)

【实验目的】

1.了解什么是信号。

2.熟悉LINUX系统中进程之间软中断通信的基本原理。 【实验原理】

利用signal来实现发送信号和接受信号的原理 【实验内容】

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

父进程等待两个子进程终止后,输出以下信息后终止: Parent process is killed!

<参考程序>

# include # include # include int wait_mark; void waiting(),stop(); void main() { int p1, p2; signal(SIGINT,stop); while((p1=fork())==-1); if(p1>0) { ①

while((p2=fork())= =-1); If(p2>0) { ②

wait_mark=1; waiting(0); kill(p1,10); kill(p2,12); wait( );

/*在父进程中*/

/*在父进程中*/

wait( );

printf(“parent process is killed!\\n”);

exit(0); } else {

wait_mark=1; signal(12,stop); waiting(); lockf(1,1,0);

printf(“child process 2 is killed by parent!\\n”); lockf(1,0,0); exit(0); } } else { } }

void waiting() {

while(wait_mark!=0); }

void stop() {

wait_mark=0; }

实验要求:

⑴ 运行程序并分析结果。

⑵ 如果把signal(SIGINT,stop)放在①号和②号位置,结果会怎样并分析原因。 ⑶ 该程序段前面部分用了两个wait(0),为什么?

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

wait_mark=1; signal(10,stop);

waiting(); lockf(1,1,0);

printf(“child process 1 is killed by parent!\\n”); lockf(1,0,0); exit(0);

/*在子进程1中*/

/*在子进程2中*/

5.2信号机制实验(二)

【实验目的】

学习signal的函数的使用

【实验原理】

利用signal的函数的机制来实习我们发送截获信号的功能 【实验内容】

修改上面的程序,增加语句signal(SIGINT,SIG_IGN)和语句signal(SIGQUIT,SIG_IGN),再观察程序执行时屏幕上出现的现象,并分析其原因。 <参考程序>

# include # include # include int pid1, pid2; int EndFlag=0; pf1=0; pf2=0; void IntDelete() {

kill(pid1,10); kill(pid2,12); EndFlag=1; } void Int1() {

printf(“child process 1 is killed by parent !\\n”); exit(0); } void Int2() {

printf(“child process 2 is killed by parent !\\n”); exit(0); } main() {

int exitcode;

signal(SIGINT,SIG_IGN); signal(SIGQUIT,SIG_IGN); while((pid1=fork())==-1); if(pid1==0) {

signal(SIGUSR1,Int1); signal(SIGINT,SIG_IGN); pause(); exit(0); } else {

while((pid2=fork())= =-1); if(pid2==0) {

signal(SIGUSR2,Int2); signal(SIGINT,SIG_IGN); pause(); exit(0); } else {

signal(SIGINT,IntDelete); waitpid(-1,&exitcode,0); exit(0); }

} } 实验要求:

运行程序并分析结果。

/*等待任何子进程中断或结束*/

printf(“parent process is killed \\n”);

⑶司机售票员问题(选做题)

编程用fork()创建一个子进程代表售票员,司机在父进程中,再用系统调用signal()让父进程(司机)捕捉来自子进程(售票员)发出的中断信号,让子进程(售票员)捕捉来自(司机)发出的中断信号,以实现进程间的同步运行。

5.3管道通信实验(一)

【实验目的】

1、了解什么是管道

2、熟悉UNIX/LINUX支持的管道通信方式 【实验内容】

编写程序实现进程的管道通信。用系统调用pipe( )建立一管道,二个子进程P1和P2分别向管道各写一句话:

Child 1 is sending a message! Child 2 is sending a message!

父进程从管道中读出二个来自子进程的信息并显示(要求先接收P1,后P2)。 参考程序

#include #include #include 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!\"); /*把串放入数组outpipe中*/

write(fd[1],outpipe,50); /*向管道写长为50字节的串*/ sleep(5); /*自我阻塞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); /*从管道中读长为50字节的串*/ printf(\"%s/n\ wait(0);

read(fd[0],inpipe,50); printf(\"%s/n\ exit(0); } } }

五、运行结果 延迟5秒后显示

child 1 process is sending message! 再延迟5秒

child 2 process is sending message!

5.4管道通信实验(二)

【实验目的】

1、掌握有名管道的创建和读写方式

2、熟悉UNIX/LINUX支持的有名管道通信方式 【实验内容】 1. 创建有名管道

2. 本进程执行循环等待数据被写入到管道中并读有名管道 3. 打开有名管道并写数据到名管道 参考代码:

//read_fifo.c #include #include #include #include #include #include #include

#define BUFFER_SIZE

int main(int argc, char **argv) { int fd;

if (argc < 2) {

fprintf(stdout, \"Usage: %s <>\\n\ exit(1); }

//int open(const char *path, int oflag, ...); if ((fd = open(argv[1], O_RDONLY)) < 0) {

fprintf(stderr, \"open fifo %s for reading failed: %s\\n\ exit(1); }

fprintf(stdout, \"open fifo %s for reading successed.\\n\ char buffer[BUFFER_SIZE];

1024

ssize_t n;

while (1) { again:

//ssize_t read(int fd, void *buf, size_t count); if ((n = read(fd, buffer, BUFFER_SIZE)) < 0) {

if (errno == EINTR) { goto again; } else {

fprintf(stderr, \"read failed on %s: %s\\n\ exit(1); } }

else if (n == 0) {

fprintf(stderr, \"peer closed fifo.\\n\"); break; } else {

buffer[n] = '\\0';

fprintf(stdout, \"read %d bytes from fifo: %s\\n\ } } return 0; }

// write_fifo.c #include #include #include #include #include #include #include #include

#define BUFFER_SIZE

void signal_handler(int s);

1024

int main(int argc, char **argv) { int fd;

if (argc < 2) {

fprintf(stdout, \"Usage: %s <>\\n\ exit(1); }

signal(SIGPIPE, signal_handler);

//int open(const char *path, int oflag, ...); if ((fd = open(argv[1], O_WRONLY)) < 0) {

fprintf(stderr, \"open fifo %s for writting failed: %s\\n\ exit(1); }

fprintf(stdout, \"open fifo %s for writting successed.\\n\

char buffer[BUFFER_SIZE]; ssize_t n;

//char *fgets(char *s, int size, FILE * stream); while (fgets(buffer, BUFFER_SIZE, stdin)) { again:

//ssize_t write(int fd, const void *buf, size_t count); if ((n = write(fd, buffer, strlen(buffer))) < 0) {

if (errno == EINTR) { goto again; } else {

fprintf(stderr, \"write() failed on fifo: %s\\n\ // FIXME: break; } } }

return 0; }

void signal_handler(int s) {

fprintf(stdout, \"Caught signal %d\\n\}

// create_fifo.c #include #include #include #include #include

int main(int argc, char **argv) {

if (argc < 2) {

fprintf(stdout, \"Usage: %s <>\\n\exit(1); }

//int mkfifo(const char *path, mode_t mode); if (mkfifo(argv[1], 04) < 0) {

fprintf(stderr, \"mkfifo() failed: %s\\n\exit(1); }

return 0; }

5.5共享内存通信实验

【实验目的】

1、掌握共享内存的创建和读写方式

2、熟悉UNIX/LINUX支持的共享内存通信方式 【实验内容】 1. 创建共享内存 2. 写入到共享内存 3. 读数据从共享内存

代码参考: //write.c

#include #include #include #include #include #include #include #include #include

#define MAPPED_ \"/tmp/test.mmap.1\"

int main(int argc, char **argv) { int fd;

if (argc < 2) {

fprintf(stdout, \"Usage: %s <>\\n\ exit(1); }

// XXX: step 1, open file, get a fd

//int open(const char *pathname, int flags, mode_t mode); if ((fd = open(argv[1], O_RDWR | O_CREAT | O_EXCL, 04)) < 0) {

if (errno == EEXIST) {

fprintf(stderr, \"Fatal error: The target mapped , exit.\\n\"); } else {

fprintf(stderr, \"Error: open : (errno = %d)%s\\n\ }

exit(1); }

off_t offset;

offset = 1024;

// XXX: step 2, create a hole file

//off_t lseek(int fildes, off_t offset, int whence);

if (lseek(fd, offset, SEEK_SET) == (off_t) - 1) {

fprintf(stderr, \"lseek() failed: %s\\n\ //FIXME: unlink the file close(fd); exit(1); }

ssize_t n;

//ssize_t write(int fd, const void *buf, size_t count); if ((n = write(fd, \"\ {

fprintf(stderr, \"write() failed: %s\\n\ exit(1); } /*

* On success, mmap returns a pointer to the mapped area. On error, the value MAP_FAILED (that is, (void*) -1) is returned, and errno is set appropriately. On success, munmap returns 0, on failure -1, and errno is set (probably to EINVAL). */ /*

PROT_EXEC Pages may be executed. PROT_READ Pages may be read. PROT_WRITE Pages may be written. PROT_NONE Pages may not be accessed. */

void *p;

// XXX: step 3, mmap(), get a pointer

//void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset); if ((p = mmap(NULL, 1024, PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {

fprintf(stderr, \"mmap() failed: %s\\n\ close(fd); exit(1); }

close(fd);

fprintf(stdout, \"mapped memory, size = %d\\n\

// XXX: step 4, read/write on shared memory char *banner = \"hello world.\";

//void *memcpy(void *dest, const void *src, size_t n); memcpy(p + 256, banner, strlen(banner));

// XXX: step 5, munmap();

//int munmap(void *start, size_t length);

pause();

//close(fd);

return 0; } // read.c #include #include #include #include #include #include #include #include #include

#define MAPPED_ \"/tmp/test.mmap.1\" #define BUFFER_SIZE

int main(int argc, char **argv) { int fd;

if (argc < 2) {

fprintf(stdout, \"Usage: %s <>\\n\ exit(1); }

// XXX: step 1, open file, get a fd

//int open(const char *pathname, int flags, mode_t mode); if ((fd = open(argv[1], O_RDWR)) < 0) {

1024

fprintf(stderr, \"Error: open : (errno = %d)%s\\n\ exit(1); } #if 0

off_t offset;

offset = 1024;

// XXX: step 2, create a hole file

//off_t lseek(int fildes, off_t offset, int whence); if (lseek(fd, offset, SEEK_SET) == (off_t) - 1) {

fprintf(stderr, \"lseek() failed: %s\\n\ //FIXME: unlink the file close(fd); exit(1); }

ssize_t n;

//ssize_t write(int fd, const void *buf, size_t count); if ((n = write(fd, \"\ {

fprintf(stderr, \"write() failed: %s\\n\ exit(1); } #endif /*

* On success, mmap returns a pointer to the mapped area. On error, the value MAP_FAILED (that is, (void*) -1) is returned, and errno is set appropriately. On success, munmap returns 0, on failure -1, and errno is set (probably to EINVAL). */ /*

PROT_EXEC Pages may be executed. PROT_READ Pages may be read. PROT_WRITE Pages may be written. PROT_NONE Pages may not be accessed. */

void *p;

// XXX: step 3, mmap(), get a pointer

//void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset); if ((p = mmap(NULL, 1024, PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {

fprintf(stderr, \"mmap() failed: %s\\n\ close(fd); exit(1); }

close(fd);

fprintf(stdout, \"mapped memory, size = %d\\n\

char buffer[BUFFER_SIZE];

// XXX: step 4, read/write on shared memory //void *memcpy(void *dest, const void *src, size_t n); memcpy(buffer, p+256, 32); fprintf(stdout, \"%s\\n\

// XXX: step 5, munmap();

//int munmap(void *start, size_t length);

//close(fd);

return 0; }

5.6用消息队列编写一个客户端服务器通信的程序

【实验目的】

通过此实验,学员可以熟悉消息队列的概念,并能够用消息队列编写一个客户端服务器通信的程序。

【实验原理】

本实验需要用消息队列设计一个简易的双人聊天程序(一个服务器,两个客户端)。消息队列重点在于消息类型的匹配,客户端和服务端的“通信协议”的设计。设计思想如下:

服务器端:接受客户端发来的任何信息,并根据其消息类型,转发给对应的客户端。同时,

检测是否有退出标志,有则给所有的客户端发送退出标志,等待10s后,确定客户端都退出后,删除消息队列,释放空间,并退出。

客户端:A和B,A给B发送信息,先发给服务器,由服务器根据自定义协议转发该消息给

B。同时B接受到消息后,经由服务器给A一个回执信息,以此形成简易的聊天模式。

【实验方法】

编写服务器端程序:

#define KEY_MSG 0x101 //使用共有的IPC key #define MSGSIZE 128 #include #include #include #include #include main() {

int msgid;

struct msgbuf //定义消息结构体:消息类型和消息数据 {

long mtype; char mtext[128]; } buf1, buf2;

msgid = msgget( KEY_MSG, IPC_CREAT|0666 );

while( 1 ) //无限循环,退出标志则会break {

msgrcv( msgid, &buf1, MSGSIZE, 1L, 0 ); //接受客户端1的消息

printf( \"Receive client1 message: %s\\n\打印收到的消息 if( buf1.mtext[0] == 'x' || buf1.mtext[0] == 'X' ) //若是退出标志,则给2个客户端都发退出信息 {strcpy( buf1.mtext, \"x\" ); buf1.mtype = 3L; }

buf1.mtype = 4L;

msgsnd( msgid, &buf1, MSGSIZE, 0 ); //将客户端1的消息转发给客户端2

msgrcv( msgid, &buf2, MSGSIZE, 2L, 0 ); //接受客户端2的消息 printf( \"Receive client2 message: %s\\n\打印收到的消息 if( buf2.mtext[0] == 'x' || buf2.mtext[0] == 'X' ) //若是退出标志,则给2个客户端发退出信息 {strcpy( buf2.mtext, \"x\" ); buf2.mtype = 3L;

msgsnd( msgid, &buf2, MSGSIZE, 0 );

msgsnd( msgid, &buf1, MSGSIZE, 0 ); buf1.mtype = 4L;

msgsnd( msgid, &buf1, MSGSIZE, 0 );

break;

buf2.mtype = 4L;

msgsnd( msgid, &buf2, MSGSIZE, 0 ); break;} buf2.mtype = 3L; }

sleep(5); //若退出,则先等待,以确保客户端程序退出 msgctl( msgid, IPC_RMID, NULL ); //删除消息队列,释放空间 exit(0); }

客户端1:

#define KEY_MSG 0x101 #define MSGSIZE 128 #include #include #include #include #include main() {

int msgid; struct msgbuf {

long mtype; char mtext[128]; } buf1, buf2;

msgid = msgget( KEY_MSG, 0666 ); while( 1 )

{ printf( \"input the msg to client2:\" ); gets( buf1.mtext ); buf1.mtype = 1L;

msgsnd( msgid, &buf1, MSGSIZE, 0 ); //客户端1获取消息并发往服务器

sleep(1); //等待一秒,以确保客户端2已经收到并发了回执 msgrcv( msgid, &buf2, MSGSIZE, 3L, 0 ); //准备从客户端2获取回执消息 if( buf2.mtext[0] == 'x' || buf2.mtext[0] == 'X' ) {printf( \"client1 will quit!\\n\" ); break;}

printf( \"Receive from client2, message: %s\\n\ } }

客户端2:

#define KEY_MSG 0x101 #define MSGSIZE 128 #include

msgsnd( msgid, &buf2, MSGSIZE, 0 ); //将客户端2的消息转发给客户端1

#include #include #include #include main() {

int msgid; struct msgbuf {

long mtype; char mtext[128]; } buf1, buf2;

msgid = msgget( KEY_MSG, 0666 ); while( 1 ) { // block

msgrcv( msgid, &buf2, MSGSIZE, 4L, 0 ); //等待客户端1发消息 if( buf2.mtext[0] == 'x' || buf2.mtext[0] == 'X' ) {printf( \"client2 will quit!\\n\" ); break;}

else printf( \"Receive from client1, message: %s\\n\

sleep(1); //等待一秒,以确保客户端1已经收到了回执 printf( \"input the msg to client1:\" ); gets( buf1.mtext ); buf1.mtype = 2L;

msgsnd( msgid, &buf1, MSGSIZE, 0 ); //给客户端1发送回执消息 } }

运行测试。先编译运行服务器,确保消息队列已经创建完毕,并进入等待状态。结果如下: [root@localhost root]# ./server Receive client1 message: i 'am client A

Receive client2 message: ok! I have recieved your msg,I'm client B Receive client1 message: x [root@localhost root]# 客户端A的运行结果如下: [root@localhost root]# ./client1 input the msg to client2:i 'am client A

Receive from client2, message: ok! I have recieved your msg,I'm client B input the msg to client2:x client1 will quit! [root@localhost root]# 客户端B的运行结果如下: [root@localhost root]# ./client2

Receive from client1, message: i 'am client A

input the msg to client1: ok! I have recieved your msg,I'm client B client2 will quit! [root@localhost root]#

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- dfix.cn 版权所有 湘ICP备2024080961号-1

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务