一、实验目的
Linux 系统的进程通信机构(IPC)允许在任意进程间大批量地交换数据,通过本实验,理解熟悉 Linux 支持的消息通信机制、共享存储区机制及信息量机制。
二、总体设计
2.1背景知识
系统调用函数说明、参数值及定义
l ●fork( )
创建一个新进程。
int fork( )
其中返回 int 取值意义如下:
0:创建子进程,从子进程返回的 id 值
大于 0:从父进程返回的子进程 id 值
-1:创建失败
UINX/Linux 系统把信号量、消息队列和共享资源统称为进程间通信资源(IPC resource)。提供给用户的 IPC 资源是通过一组系统调用实现的。这组系统调用为用户态进程提供了以下三种服
务:
用信号量对进程要访问的临界资源进行保护。
用消息队列在进程间以异步方式发送消息。
用一块预留出的内存区域供进程之间交换数据。
●创建 IPC 资源的系统调用有:
semget()—获得信号量的 IPC 标识符。
msgget()—获得消息队列的 IPC 标识符。
shmget()—获得共享内存的 IPC 标识符。
●控制 IPC 资源的系统调用有:
semctl()—对信号量资源进行控制的函数。
msgctl()—对消息队列进行控制的函数。
shmctl()—对共享内存进行控制的函数。
●上述函数为获得和设置资源的状态信息提供了一些命令。例如:
IPC_SET 命令:设置属主的用户标识符和组标识符。
IPC_STAT 和 IPC_INFO 命令:获得资源状态信息。
IPC_RMID 命令:释放这个资源。
●操作 IPC 资源的系统调用有:
semop()—获得或释放一个 IPC 信号量。 可以实现 P、 V 操作
msgsnd()—发送一个 IPC 消息。
msgrcv()—接收一个 IPC 消息。
shmat()—将一个 IPC 共享内存段添加到 进程的地址空间
shmdt()——将 IPC 共享内存段从私有的地址空间剥离
2.2 设计步骤
1)任务 1(消息的创建、发送和接收)的程序设计
(1) 为了便于操作和观察结果,用一个程序作为“引子”,先后 fork()两个子进程 SERVER和 CLIENT,进行通信。
(2) SERVER 端建立一个 key 为 75 的消息队列,等待其他进程发来的消息。当遇到类型为 1 的消息,则作为结束信号,取消该队列,并退出 SERVER。 SERVER 每接收到一个消息后显示一句“(server) received”。
(3) CLIENT 端使用 key 为 75 的消息队列,先后发送类型从 10 到 1 的消息,然后退出。最后的一个消息,即是 SERVER 端需要的结束信号。 CLIENT 每发送一条消息后显示一句“(client)sent”。
(4) 父进程在 SERVER 和 CLIENT 均退出后结束。
2)任务 2(共享存储区的创建、附接和断接)的程序设计
(1) 为了便于操作和观察结果,用一个程序作为“引子”,先后 fork()两个子进程 SERVER和 CLIENT,进行通信。
(2) SERVER 端建立一个 key 为 75 的消息队列,并将第一个字节置为-1,作为数据空的标志,等待其他进程发来的消息。当该字节的值发生变化时,表示收到了信息,进行处理。然后再次把它的值设为-1。当遇到的值为 0,则视为结束信号,取消该队列,并退出 SERVER。SERVER 每接收到一个消息后显示一句“(server) received”。
(3) CLIENT 端使用 key 为 75 的消息队列,当共享取得第一个字节为-1 时, SERVER端空闲,可发送请求。 CLIENT 随即填入 9 到 0。期间等待 SERVER 端的再次空闲。进 行 完 这 些 操 作 后 , CLIENT 退 出 。 CLIENT 每 发 送 一 条 消 息 后 显 示 一 句“(client)sent”。
(4) 父进程在 SERVER 和 CLIENT 均退出后结束。
三、详细设计
任务一代码:
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#define MSGKEY 75
struct msgform
{
long mtype;
char mtext[1030];
}msg;
int msgqid,i;
void CLIENT()
{
int i;
msgqid=msgget(MSGKEY,0777);
for (i=10;i>=1;i--)
{
msg.mtype=i;
printf("(client) sent \n");
msgsnd(msgqid,&msg,1024,0);
}
exit(0);
}
void SERVER()
{
msgqid=msgget(MSGKEY,0777|IPC_CREAT);
do{
msgrcv(msgqid,&msg,1030,0,0);
printf("(Server) recieved\n");
} while(msg.mtype!=1);
msgctl(msgqid,IPC_RMID,0);
exit(0);
}
int main()
{
while((i=fork())==-1);
if(!i) SERVER();
while((i=fork())==-1);
if(!i) CLIENT();
wait(0);
wait(0);
}
任务二代码:
#include <stdio.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#define MSGKEY 75
int shmid,i;
int *addr;
void CLIENT()
{
int i;
shmid=shmget(MSGKEY,1024,0777);
addr=shmat(shmid,0,0);
for (i=9;i>=0;i--)
{
while(*addr!=-1);
printf("(CLIENT) sent\n");
*addr=i;
}
exit(0);
}
void SERVER()
{
shmid=shmget(MSGKEY,1024,0777|IPC_CREAT);
addr=shmat(shmid,0,0); //shoudizhi
do{
*addr=-1;
while(*addr==-1);
printf("(Server) recieved\n");
} while(*addr);
shmctl(shmid,IPC_RMID,0);
exit(0);
}
int main()
{
while((i=fork())==-1);
if(!i) SERVER();
while((i=fork())==-1);
if(!i) CLIENT();
wait(0);
wait(0);
}
四、实验结果与分析
任务一:
消息的传送和控制并不保证完全同步,当一个个程序不在激活状态的
时候,它完全可能继续睡眠,造成了出现几个“( client) sent”连续后再几个“( server) received”,现象。实验结果如下:
任务二:
两种消息传送机制对比:
消息队列的建立比共享区的设立消耗的资源少。
消息队列由软件控制和实现,共享区的数据传输受硬件限制。
共享区的数据传输运行结果如下:
五、小结与心得体会
通过本实验,我理解熟悉了 Linux 支持的消息通信机制、共享存储区机制及信息量机制。 Linux 系统的进程通信机构(IPC)允许在任意进程间大批量地交换数据,