操作系统实验 消息的发送与接收Word下载.docx
- 文档编号:21190604
- 上传时间:2023-01-28
- 格式:DOCX
- 页数:11
- 大小:52.08KB
操作系统实验 消息的发送与接收Word下载.docx
《操作系统实验 消息的发送与接收Word下载.docx》由会员分享,可在线阅读,更多相关《操作系统实验 消息的发送与接收Word下载.docx(11页珍藏版)》请在冰豆网上搜索。
该函数使用头文件如下:
#include<
sys/types.h>
sys/ipc.h>
sys/msg.h>
参数定义
intmsgget(key,flag)
key_tkey;
intflag;
其中:
key是用户指定的消息队列的名字;
flag是用户设置的标志和访问方式。
如IPC_CREAT|0400是否该队列已被创建。
无则创建,是则打开;
IPC_EXCL|0400是否该队列的创建应是互斥的。
msgqid是该系统调用返回的描述符,失败则返回-1。
2.msgsnd()
发送一消息。
向指定的消息队列发送一个消息,并将该消息链接到该消息队列的尾部。
msgsnd(msgqid,msgp,size,flag)
#include<
参数定义:
intmsgsnd(msgqid,msgp,size,flag)
Iintmsgqid,size,flag;
structmsgbuf*msgp;
其中msgqid是返回消息队列的描述符;
msgp是指向用户消息缓冲区的一个结构体指针。
缓冲区中包括消息类型和消息正文,即
{
longmtype;
/*消息类型*/
charmtext[];
/*消息的文本*/
}
size指示由msgp指向的数据结构中字符数组的长度;
即消息的长度。
这个数组的最大值由MSG-MAX()系统可调用参数来确定。
flag规定当核心用尽内部缓冲空间时应执行的动作:
进程是等待,还是立即返回。
若在标志flag中未设置IPC_NOWAIT位,则当该消息队列中的字节数超过最大值时,或系统范围的消息数超过某一最大值时,调用msgsnd进程睡眠。
若是设置IPC_NOWAIT,则在此情况下,msgsnd立即返回。
对于msgsnd(),核心须完成以下工作:
(1)对消息队列的描述符和许可权及消息长度等进行检查。
若合法才继续执行,否则返回;
(2)核心为消息分配消息数据区。
将用户消息缓冲区中的消息正文,拷贝到消息数据区;
(3)分配消息首部,并将它链入消息队列的末尾。
在消息首部中须填写消息类型、消息大小和指向消息数据区的指针等数据;
(4)修改消息队列头中的数据,如队列中的消息数、字节总数等。
最后,唤醒等待消息的进程。
3.msgrcv()
接受一消息。
从指定的消息队列中接收指定类型的消息。
msgrcv(msgqid,msgp,size,type,flag)
本函数使用的头文件如下:
#include<
#include<
intmsgrcv(msgqid,msgp,size,type,flag)
intmsgqid,size,flag;
structmsgbuf*msgp;
longtype;
其中,msgqid,msgp,size,flag与msgsnd中的对应参数相似,type是规定要读的消息类型,flag规定倘若该队列无消息,核心应做的操作。
如此时设置了IPC_NOWAIT标志,则立即返回,若在flag中设置了MS_NOERROR,且所接收的消息大于size,则核心截断所接收的消息。
对于msgrcv系统调用,核心须完成下述工作:
(1)对消息队列的描述符和许可权等进行检查。
若合法,就往下执行;
否则返回;
(2)根据type的不同分成三种情况处理:
type=0,接收该队列的第一个消息,并将它返回给调用者;
type为正整数,接收类型type的第一个消息;
type为负整数,接收小于等于type绝对值的最低类型的第一个消息。
(3)当所返回消息大小等于或小于用户的请求时,核心便将消息正文拷贝到用户区,并从消息队列中删除此消息,然后唤醒睡眠的发送进程。
但如果消息长度比用户要求的大时,则做出错返回。
4.msgctl()
消息队列的操纵。
读取消息队列的状态信息并进行修改,如查询消息队列描述符、修改它的许可权及删除该队列等。
msgctl(msgqid,cmd,buf);
intmsgctl(msgqid,cmd,buf);
intmsgqid,cmd;
structmsgqid_ds*buf;
其中,函数调用成功时返回0,不成功则返回-1。
buf是用户缓冲区地址,供用户存放控制参数和查询结果;
cmd是规定的命令。
命令可分三类:
(1)IPC_STAT。
查询有关消息队列情况的命令。
如查询队列中的消息数目、队列中的最大字节数、最后一个发送消息的进程标识符、发送时间等;
(2)IPC_SET。
按buf指向的结构中的值,设置和改变有关消息队列属性的命令。
如改变消息队列的用户标识符、消息队列的许可权等;
(3)IPC_RMID。
消除消息队列的标识符。
msgqid_ds结构定义如下:
structmsgqid_ds
{structipc_permmsg_perm;
/*许可权结构*/
shortpad1[7];
/*由系统使用*/
ushortmsg_qnum;
/*队列上消息数*/
ushortmsg_qbytes;
/*队列上最大字节数*/
ushortmsg_lspid;
/*最后发送消息的PID*/
ushortmsg_lrpid;
/*最后接收消息的PID*/
time_tmsg_stime;
/*最后发送消息的时间*/
time_tmsg_rtime;
/*最后接收消息的时间*/
time_tmsg_ctime;
/*最后更改时间*/
};
structipc_perm
{ushortuid;
/*当前用户*/
ushortgid;
/*当前进程组*/
ushortcuid;
/*创建用户*/
ushortcgid;
/*创建进程组*/
ushortmode;
/*存取许可权*/
{shortpid1;
longpad2;
}/*由系统使用*/
(三)、参考程序
1、client.c
#defineMSGKEY75
structmsgform
{longmtype;
charmtext[1000];
}msg;
intmsgqid;
voidclient()
inti;
msgqid=msgget(MSGKEY,0777);
/*打开75#消息队列*/
for(i=10;
i>
=1;
i--)
msg.mtype=i;
printf(“(client)sent\n”);
msgsnd(msgqid,&
msg,1024,0);
/*发送消息*/
}
exit(0);
main()
{
client();
2、server.c
voidserver()
msgqid=msgget(MSGKEY,0777|IPC_CREAT);
/*创建75#消息队列*/
do
{
msgrcv(msgqid,&
msg,1030,0,0);
/*接收消息*/
printf(“(server)received\n”);
}while(msg.mtype!
=1);
msgctl(msgqid,IPC_RMID,0);
/*删除消息队列,归还资源*/
server();
(四)、程序说明
1、为了便于操作和观察结果,编制二个程序client.c和server.c,分别用于消息的发送与接收。
2、server建立一个Key为75的消息队列,等待其它进程发来的消息。
当遇到类型为1的消息,则作为结束信号,取消该队列,并退出server。
server每接收到一个消息后显示一句“(server)received。
”
3、client使用key为75的消息队列,先后发送类型从10到1的消息,然后退出。
最后一个消息,即是server端需要的结束信号。
client每发送一条消息后显示一句“(client)sent”。
4、注意:
二个程序分别编辑、编译为client与server。
执行:
./server&
ipcs-q
./client。
(五)、运行结果
从理想的结果来说,应当是每当client发送一个消息后,server接收该消息,client再发送下一条。
也就是说“(client)sent”和“(server)received”的字样应该在屏幕上交替出现。
实际的结果大多是,先由client发送了两条消息,然后server接收一条消息。
此后client、server交替发送和接收消息。
最后server一次接收两条消息。
client和server分别发送和接收了10条消息,与预期设想一致。
(六)、思考
message的传送和控制并不保证完全同步,当一个程序不在激活状态的时候,它完全可能继续睡眠,造成了上面的现象,在多次sendmessage后才recievemessage。
这一点有助于理解消息传送的实现机理。
【附加:
共享存储区的创建,附接和断接来实现进程通信《留给有时间的同学看》
<
任务>
使用系统调用shmget(),sgmat(),smgdt(),shmctl()编制一个与上述功能相同的程序.
程序设计>
(1)为了便于操作和观察结果,用一个程序为“引子”,先后fork()两个子进程,SERVER和CLIENT,进行通信。
(2)SERVER端建立一个KEY为75的共享区,并将第一个字节置为-1.作为数据空的标志.等待其他进程发来的消息.当该字节的值发生变化时,表示收到了该消息,进行处理.然后再次把它的值设为-1.如果遇到的值为0,则视为结束信号,取消该队列,并退出SERVER.SERVER每接收到一次数据后显示”(server)received”.
(3)CLIENT端建立一个为75的共享区,当共享取得第一个字节为-1时,Server端空闲,可发送请求.CLIENT随即填入9到0.期间等待Server端再次空闲.进行完这些操作后,CLIENT退出.CLIENT每发送一次数据后显示”(client)sent”.
(4)父进程在SERVER和CLIENT均退出后结束.
程序>
#defineSHMKEY75/*定义共享区关键词*/
intshmid,i;
int*addr;
void*shmat();
/*如果去掉这行,看看运行结果,分析为什么*/
CLIENT()
inti;
shmid=shmget(SHMKEY,1024,0777|IPC_CREAT);
/*获取共享区,长度1024,关键词SHMKEY*/
addr=shmat(shmid,0,0);
/*共享区起始地址为addr*/
for(i=9;
=0;
i--)
{
while(*addr!
=-1);
printf("
(client)sent\n"
);
/*打印(client)sent*/
*addr=i;
/*把i赋给addr*/
}
exit(0);
SERVER()
{
do
{
while(*addr==-1);
(server)received\n%d"
*addr);
/*服务进程使用共享区*/
if(*addr!
=0)
*addr=-1;
}while(*addr);
wait(0);
shmctl(shmid,IPC_RMID,0);
main()
shmid=shmget(SHMKEY,1024,0777|IPC_CREAT);
/*创建共享区*/
if(fork())
{
SERVER();
else
CLIENT();
结果〉
运行的结果和预想的完全一样。
但在运行的过程中,发现每当client发送一次数据后,server要等大约0.1秒才有响应。
同样,之后client又需要等待大约0.1秒才发送下一个数据。
分析〉
出现上述的应答延迟的现象是程序设计的问题。
当client端发送了数据后,并没有任何措施通知server端数据已经发出,需要由client的查询才能感知。
此时,client端并没有放弃系统的控制权,仍然占用CPU的时间片。
只有当系统进行调度时,切换到了server进程,再进行应答。
这个问题,也同样存在于server端到client的应答过程之中。
3比较两种消息通信机制中的数据传输的时间
由于两种机制实现的机理和用处都不一样,难以直接进行时间上的比较。
如果比较其性能,应更加全面的分析。
(1)消息队列的建立比共享区的设立消耗的资源少.前者只是一个软件上设定的问题,后者需要对硬件操作,实现内存的映像,当然控制起来比前者复杂.如果每次都重新进行队列或共享的建立,共享区的设立没有什么优势。
(2)当消息队列和共享区建立好后,共享区的数据传输,受到了系统硬件的支持,不耗费多余的资源;
而消息传递,由软件进行控制和实现,需要消耗一定的CPU资源.从这个意义上讲,共享区更适合频繁和大量的数据传输.
(3)消息的传递,自身就带有同步的控制.当等到消息的时候,进程进入睡眠状态,不再消耗CPU资源.而共享队列如果不借助其他机制进行同步,接受数据的一方必须进行不断的查询,白白浪费了大量的CPU资源.可见消息方式的使用更加灵活.
】
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统实验 消息的发送与接收 操作系统 实验 消息 发送 接收