操作系统实验 消息的发送与接收.docx

上传人:b****4 文档编号:678885 上传时间:2022-10-12 格式:DOCX 页数:12 大小:135.89KB
下载 相关 举报
操作系统实验 消息的发送与接收.docx_第1页
第1页 / 共12页
操作系统实验 消息的发送与接收.docx_第2页
第2页 / 共12页
操作系统实验 消息的发送与接收.docx_第3页
第3页 / 共12页
操作系统实验 消息的发送与接收.docx_第4页
第4页 / 共12页
操作系统实验 消息的发送与接收.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

操作系统实验 消息的发送与接收.docx

《操作系统实验 消息的发送与接收.docx》由会员分享,可在线阅读,更多相关《操作系统实验 消息的发送与接收.docx(12页珍藏版)》请在冰豆网上搜索。

操作系统实验 消息的发送与接收.docx

操作系统实验消息的发送与接收

操作系统实验消息的发送与接收

MSG

一、实验目的

1、了解什么是消息

2、熟悉消息传送的机理。

二、实验内容

   消息的创建、发送和接收。

使用系统调用msgget(),msgsnd(),msgrev(),及msgctl()编制一长度为1k的消息发送和接收的程序

三、实验内容指导提示

(一)、什么是消息

消息(message)是一个格式化的可变长的信息单元。

消息机制允许由一个进程给其它任意的进程发送一个消息。

当一个进程收到多个消息时,可将它们排成一个消息队列。

消息使用二种重要的数据结构:

一是消息首部,其中记录了一些与消息有关的信息,如消息数据的字节数;二个消息队列头表,其每一表项是作为一个消息队列的消息头,记录了消息队列的有关信息。

1、消息机制的数据结构

(1)消息首部

记录一些与消息有关的信息,如消息的类型、大小、指向消息数据区的指针、消息队列的链接指针等。

(2)消息队列头表

其每一项作为一个消息队列的消息头,记录

IPC_NOWAIT位,则当该消息队列中的字节数超过最大值时,或系统范围的消息数超过某一最大值时,调用msgsnd进程睡眠。

若是设置IPC_NOWAIT,则在此情况下,msgsnd立即返回。

对于msgsnd(),核心须完成以下工作:

(1)对消息队列的描述符和许可权及消息长度等进行检查。

若合法才继续执行,否则返回;

(2)核心为消息分配消息数据区。

将用户消息缓冲区中的消息正文,拷贝到消息数据区;

(3)分配消息首部,并将它链入消息队列的末尾。

在消息首部中须填写消息类型、消息大小和指向消息数据区的指针等数据;

(4)修改消息队列头中的数据,如队列中的消息数、字节总数等。

最后,唤醒等待消息的进程。

3.msgrcv()

接受一消息。

从指定的消息队列中接收指定类型的消息。

系统调用格式:

msgrcv(msgqid,msgp,size,type,flag)

本函数使用的头文件如下:

#include

#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);

本函数使用的头文件如下:

#include

#include

#include

参数定义:

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

#include

#include

#include

#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

#include

#include

#include

#defineMSGKEY75

structmsgform

{longmtype;

charmtext[1000];

}msg;

intmsgqid;

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);/*删除消息队列,归还资源*/

exit(0);

}

main()

{

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均退出后结束.

<程序>

#include

#include

#include

#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;i>=0;i--)

{

while(*addr!

=-1);

printf("(client)sent\n");/*打印(client)sent*/

*addr=i;/*把i赋给addr*/

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 人文社科 > 法律资料

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1