一:实验题目
Linux 进程间通信
二:实验目的
Linux 系统的进程通信机构(IPC)允许在任意进程间大批量地交换数据,通过本实验,理解
熟悉 Linux 支持的消息通信机制。
三:实验内容(实验原理/运用的理论知识、算法/程序流程图、步骤和方法、关键代码)
实验原理:主要用到4个函数
int msgget(key_t key, int msgflag);
key:某个消息队列的名字,用frok()产生 (函数frok的返回值)或IPC_PRIVATE,获取消息队列的标识符,创建和访问一个消息队列。
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msqid:消息队列标识符,由msgget获得;
cmd:控制标识符,IPC_SET 命令:设置属主的用户标识符和组标识符,IPC_STAT 和 IPC_INFO 命令:获得资源状态信息,IPC_RMID 命令:释放这个资源;
buf:消息队列管理结构体,请参见消息队列内核结构说明部分。
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msqid:消息队列标识符;
msgp:发送给队列的消息。msgp可以是任何类型的结构体,但第一个字段必须为long类型,即表明此发送消息的类型,msgrcv根据此接收消息。msgp定义的参照格式如下:
struct s_msg{ /*msgp定义的参照格式*/
long type; /* 必须大于0,消息类型 */
char mtext[256]; /*消息正文,可以是其他任何类型*/
} msgp;
msgsz:要发送消息的大小,不含消息类型占用的4个字节,即mtext的长度;
msgflg:控制位,规定当核心用尽内部缓冲空间时应执行的动作
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
msqid:消息队列标识符;
msgp:存放消息的结构体,结构体类型要与msgsnd函数发送的类型相同;
msgsz:要接收消息的大小,不含消息类型占用的4个字节;
msgtyp:0:接收第一个消息;>0:接收类型等于msgtyp的第一个消息;<0:接收类型等于或者小于msgtyp绝对值的第一个消息;
msgflg:规定倘若该队列无消息,核心应当做什么事,如果此时设置了 IPC_NOWAIT 标志,则立即返回,若在 flag 中设置了 MSG_NOERROR,且所接收的消息大小大于 size ,核心截断所接收的消息。
msgrcv()解除阻塞的条件有以下三个:
1.消息队列中有了满足条件的消息。
2.msqid代表的消息队列被删除。
3.调用msgrcv()的进程被信号中断。
用以上4个函数实现Linux系统下的通信。
四:实验结果与分析
结果分析:
程序首先创建一个消息队列,用于进程间的消息传递。使用msgget()函数创建消息队列,并指定消息队列的键值为MSGKEY。
然后程序通过调用fork()函数创建子进程。子进程中调用SERVER()函数作为服务器进程,父进程中调用CLIENT()函数作为客户端进程。
服务器进程通过调用msgrcv()函数接收消息,并打印出"(Server) received"。服务器进程会一直接收消息,直到接收到消息类型为1的消息。
客户端进程通过调用msgsnd()函数向消息队列发送消息,并打印出"(client) sent"。客户端进程发送10个不同类型的消息,从10到1。
服务器进程接收到消息类型为1的消息后,调用msgctl()函数删除消息队列,并退出进程。
主进程通过两次调用wait()函数等待子进程的结束。
分析:
客户端进程先运行,连续发送10个消息到消息队列。
服务器进程接收到第一个消息时打印"(Server) received",然后进入循环等待接收其他消息。
当服务器进程接收到类型为1的消息时,即第十个消息,打印"(Server) received"。
主进程等待子进程的结束。
请注意,由于进程调度的不确定性和消息传递的异步性,实际运行结果可能会有所不同。以上结果仅代表可能的一种情况。
五、小结与心得体会
1.进程间通信:这个实验通过消息队列实现了进程间的通信。服务器进程通过msgrcv()函数接收消息,客户端进程通过msgsnd()函数发送消息。消息队列提供了一种可靠的通信机制,使得进程可以在异步的情况下进行交互。
2.消息队列:消息队列是一种存放消息的容器,进程可以向队列中发送消息,也可以从队列中接收消息。每个消息都有一个消息类型,用于标识不同的消息。在这个实验中,服务器进程通过指定消息类型为0来接收所有类型的消息,直到接收到类型为1的消息。
3.进程间同步:在实验中,服务器进程在接收到特定类型的消息后才会退出。这种方式实现了进程间的同步,保证服务器进程在接收到指定的消息之前一直等待。
4.fork()函数的使用:实验中使用了fork()函数创建子进程。通过多次调用fork()函数,实现了创建服务器进程和客户端进程的目的。子进程会继承父进程的消息队列标识符,因此可以进行消息的发送和接收。
5.父子进程的协作:通过fork()函数创建的子进程在执行不同的函数,实现了父子进程的协作。客户端进程发送消息,服务器进程接收消息,彼此配合完成通信任务。
6.异步消息传递:由于消息传递是异步的,客户端进程可以快速发送多个消息,而服务器进程可以在自己的节奏下接收这些消息。这种异步性可以提高系统的响应速度和并发性能。