西北工业大学 操作系统 实验七.docx

上传人:b****5 文档编号:3231665 上传时间:2022-11-20 格式:DOCX 页数:9 大小:143.31KB
下载 相关 举报
西北工业大学 操作系统 实验七.docx_第1页
第1页 / 共9页
西北工业大学 操作系统 实验七.docx_第2页
第2页 / 共9页
西北工业大学 操作系统 实验七.docx_第3页
第3页 / 共9页
西北工业大学 操作系统 实验七.docx_第4页
第4页 / 共9页
西北工业大学 操作系统 实验七.docx_第5页
第5页 / 共9页
点击查看更多>>
下载资源
资源描述

西北工业大学 操作系统 实验七.docx

《西北工业大学 操作系统 实验七.docx》由会员分享,可在线阅读,更多相关《西北工业大学 操作系统 实验七.docx(9页珍藏版)》请在冰豆网上搜索。

西北工业大学 操作系统 实验七.docx

西北工业大学操作系统实验七

 

西北工业大学

《操作系统》实验报告

 

 

姓名:

学号:

班级:

地点:

日期:

 

西北工业大学

实验七、消息及其传送机制

一、Unix系统的消息机制:

在Unix操作系统的内部结构中,含有消息机构,即所有的消息都放在内核中,并且它们都有一个相应的Unix消息队列号。

消息机构允许进程发送一个消息到任意其它进程,从而实现系统中进程间的通信。

二、Unix操作系统中的消息机构

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

它有如下属性:

(1)长整数类型

(2)消息的数据长度

(3)数据。

由于消息的长度是可变的,故将消息分为消息首部和消息数据两部分。

在消息首部中,记录着消息的类型和大小,指向消息数据区的指针,Unix消息队列的链接指针等。

每个消息队列有一个称为key的名称,如同用户文件描述符一样,每个Unix消息队列还有一个消息队列描述符。

此外,在一个系统中,可能有若干个Unix消息队列,所有Unix消息队列的头标组成一个数组。

1.Unix操作系统建立或返回Unix消息队列描述符

进程可用系统调用megget来建立或返回Unix消息队列的描述符。

该系统调用的语法格式为:

1.intmegget(key,msgflg)

2.key_tkey;

3.intmegflg;

其中,key是Unix消息队列的名字;msgflg是用户设置的标志。

如果IPC_CREAT表示系统无以key命名的消息队列,则建立消息队列标识符;若已存在,则返回Unix消息队列描述符msgid。

对于系统调用,核心将搜索Unix消息队列头标数组,确定是否有指定关键字的Unix消息队列。

若无,核心将分配一新的队列结构,并返回给用户一个Unix消息队列描述符;否则,它只是检查Unix消息队列的许可权之后便返回。

2.Unix操作系统消息的发送

进程可用megsnd()系统调用来发送一个消息,并将它链入Unix消息队列的尾部。

该系统调用的语法格式如下:

1.intmsgsnd(msgid,msgp,msgsz,msgflg)

2.intmsgid;

3.structmsgbuf*msgp;

4.intmsgsz,msgflg;

其中,msgid是由msgget返回的Unix消息队列描述符;msgp指向包含这条消息的结构,该结构由如下两个成员组成:

1.structmsgbuf

2.{longmtype;/*消息类型*/

3.charmtext[];/*消息的文本*/}msgsz是mtext的字节长度;msgflg规定了当无内存空间来存储消息时,进程等待还是立即返回。

对于msgsnd()系统调用,核心检查消息队列描述符和许可权是否合法;消息长度是否超过系统规定的长度,若过长,进程睡眠等待出现足够大的空间,通过检查后,核心为消息分配消息数据区,并将消息从用户空间拷贝到消息数据区,分配消息首部,将它链入该Unix消息队列的尾部,在消息首部填写消息类型,大小以及指向消息数据区的指针,还有修改消息队列的头标中的数据。

然后唤醒在等待消息到来的队列中睡眠的进程。

3.Unix操作系统消息的接收

进程可用msgrcv()系统调用,从Unix消息队列中读一条消息,语法格式为:

1.intmsgrcv(msgid,msgp,msgsz,msgtyp,msgflg)

2.intmsgid,msgsz,msgflg;

3.structmsgbuf*msgp;

4.longmsgtyp;

其中,msgid,msgp,msgsz,msgflg与msgsnd相似,msgtype是规定用户想读的消息类型。

对于msgrcv()系统调用是先由核心检查消息队列标识符和许可权,接着根据msgtyp分三种情况处理。

(1)msgtyp=0,核心寻找Unix消息队列中的第一个消息,并将它返回给调用进程;

(2)msgtyp为正整数,核心返回给类型的第一个消息;(3)msgtyp为负整数,核心应在其类型值小于或等于msgtyp绝对值的所有消息中,选择类型最低的第一消息返回。

如果所返回的消息的大小等于或小于用户请求,核心便将消息正文拷贝到用户区,再从队列中删除该消息,并唤醒睡眠的发送进程;如果消息比用户要求的大,则系统返回错误信息。

4.Unix操作系统Unix消息队列的操纵

可利用msgctl()系统调用,来改变Unix消息队列的属性,即拥有者,许可权等。

其语法格式如下:

1.intmsgctl(msgid,cmd,buf)

2.intmsgid,cmd;

3.structmsgid_ds*buf;其中,cmd是规定的命令;buf是用户缓冲区地址,用户用它来存放控制参数和查询结果。

命令可分为三类:

(1)用于查询有关Unix消息队列的情况。

(2)用于改变有关Unix消息队列的属性。

(3)消除Unix消息队列的标识符。

三、Unix操作系统多路复用消息

在客户-服务员模型中,一个服务员往往对应多个客户。

这时我们可以利用消息的类型参量,让多个进程把消息放入同一个队列中,以便Unix消息队列能够多路复用。

如图2所示,我们只要把type置为1,以表示消息是从客户流向服务员的。

如果客户把它的进程号作为消息的一部分传递,那么服务员只要把客户进程号作为其消息类型,把它的消息发送给客户进程。

每个客户进程都把msgrcv的参数msgtyp置为其进程号。

二、消息的创建、发送和接收的实验步骤:

1.编制两个程序client.c和server.c,分别用于消息的发送和接收。

2.client与server均建立关键字为75的消息队列

所编代码如下:

参考程序

client.c

#include

#include

#include

#include

#include

#defineMSGKEY75/*定义一个消息关键字*/

structmsgform/*定义一个结构,它是一个消息的模式,只说明结构的形式*/

{longmtype;/*消息类型*/

charmtext[256];/*消息正文数组*/

};

intmain(){

{structmsgformmsg;/*定义msg是前面说明的消息结构类型的变量*/

intmsggid,pid,*pint;

msggid=msgget(MSGKEY,0777);/*用系统调用创建一个消息队列*/

pid=getpid();/*获得当前进程的PID*/

printf(“client:

pid=%d\n”,pid);

pint=(int*)msg.mtext;/*将消息正文的头指针赋给指针变量pint*/

*pint=pid;

msg.mtype=1;/*指定客户进程的消息类型为1*/

msgsnd(msggid,&msg,sizeof(int),0);/*向msggid的消息队列发送消息msg*/

msgrcv(msggid,&msg,256,pid,0);/*接收pid类型的消息*/

printf(“client:

receivefrompid%d\n”,*pint);

return0;

}

server.c

#include

#include

#include

#include

#include

#include

#include

#defineMSGKEY75/*定义一个消息关键字*/

structmsgform/*定义一个与客户端相同的消息关键字*/

{longmtype;/*消息类型*/

charmtext[256];/*消息正文数组*/

}msg;/*也可以使用这种方式说明消息结构变量*/

voidcleanup(intsigno);/*说明一个外部函数*/

intmsggid;

intmain()

{

inti,pid,*pint;

for(i=0;i<23;i++)/*对22个软中断的特殊处理*/

signal(i,cleanup);/*若收到22个软中断,转向执行cleanup*/

msggid=msgget(MSGKEY,0777|IPC_CREAT);

/*创建一个与客户程序相同关键字的消息队列,但它的标志是0777与IPC_CREAT做“或”操作的结果*/

printf(“server:

pid=%d\n”,getpid());/*输出服务端的进程ID*/

for(;;)/*用无限循环完成下列语句*/

{msgrcv(msggid,&msg,256,1,0);/*接收来自客户进程或类型为1的消息*/

pint=(int*)msg.mtext;/*将客户端的消息正文传递给pint*/

pid=*pint;//将读出消息指针送pid,此时*pint中是客户进程的pid值printf(“server:

receivefrompid%d\n”,pid);

msg.mtype=pid;/*已接受客户进程的pid为消息类型*/

*pint=getpid();/*以本进程pid作为消息构成消息传递内容*/

msgsnd(msggid,&msg,sizeof(int),0);/*发送消息*/

}

}

voidcleanup(intsigno)

{msgctl(msggid,IPC_RMID,0);/*删除消息队列*/

exit(0);

}

注意:

二个程序分别编辑、编译为client与server。

执行:

./server&

./client

或者在2个控制台执行程序。

执行一次server,执行多次client结果如下:

 

单独执行server与client结果如下:

思考

1)、单独执行client或server有什么结果?

答:

运行./server然后发现根本就停不下来,于是按下ctrl+c,之后再输入./client,结果如上图所示。

上面显示的是两次结果。

2)、执行一个server程序,多次执行client有什么结果?

答:

先运行./server&,即让server程序先在后台运行,让后多次执行./client,运行的结果如图一所示。

显示表明每次运行的结果都可能是不同的,而且有局部效应。

即PID号总是在某个区域内变化。

3)、消息机制与管道通信的区别?

答:

管道通信(PIPE)

管道通信方式的中间介质是文件,通常称这种文件为管道文件。

两个进程利用管道文件进行通信时,一个

进程为写进程,另一个进程为读进程。

写进程通过写端(发送端)往管道文件中写入信息;读进程通过读

端(接收端)从管道文件中读取信息。

两个进程协调不断地进行写、读,便会构成双方通过管道传递信息

的流水线。

利用系统调用PIPE()创建一个无名管道文件,通常称为无名管道或PIPE;利用系统调用MKNOD()创建

一个有名管道文件,通常称为有名管道或FIFO。

PIPE是一种非永久性的管道通信机构,当它访问的进程全部终止时

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

当前位置:首页 > 成人教育 > 自考

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

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