实验三 - 进程间通信(1)(3)

2019-08-30 13:12

IPC_NOWAIT ——没有可以接收的消息时,立即返回-1 MSG_EXCEPT ——返回第一个类型不为msgtyp的消息

MSG_NOERROR——消息正文长度超过msgsz字节时,将直接截去其

中多余的部分

③功能: 如果传递给参数msgflg的值为IPC_NOWAIT,并且没有可取的消息,

那么给调用进程返回ENOMSG错误码,否则,调用进程阻塞,直到一条满足要求的消息到达消息队列。如果进程正在等待消息,而相应的消息队列被删除,则返回EIDRM。如果当进程正在等待消息时,捕获到了一个信号,则返回EINTR

④返回值: 接收成功,返回实际接收到的消息正文的字节数;否则返回-1,同

时error中存有错误代码

⑤错误代码:E2BIG ——消息长度超过msgsz,且MSG_NOERROR标志没被使用

EACCESS——无权限读取消息队列

EFAULT ——参数msgp指向的地址无法访问

EIDRM ——标识符为msqid的消息队列已被删除 EINTR ——等待消息的情况下,被信号唤醒

EINVAL ——无效的参数msqid、或msgsz为负数 ENOMSG ——参数msgflg设为IPC_NOWAIT,但无满足要求的消息

可接收

(4)msgctl系统调用

①函数原型:

#include #include #include

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

②参数:

msqid 消息队列的标识数 cmd IPC_STAT ——将对应消息队列结构体的值复制到一份到buf所

指的结构体中,调用者必须有读消息队列的权限

IPC_SET —— 将buf所指结构体中的部分信息:

msg_perm.uid,msg_perm.gid,mst_perm.mode,msg_qbytes写到消息队列结构体中,并且更新消息队列结构体msg_ctime成员的值。调用者必须有相应的权限。

IPC_RMD —— 删除消息队列,并唤醒该消息队列上等待读或等待写

的进程。调用者必须有相应的权限。

③功能: 获取或设置消息队列的属性信息,或者删除消息队列 ④返回值: 成功,返回0;否则返回-1,同时error中存有错误代码

⑤错误代码:EACCESS—— cmd为IPC_STAT,但调用进程无读消息队列的权限

EFAULT —— 参数cmd为IPC_STAT或IPC_SET ,但buf指向的

地址无法访问

EIDRM ——标识符为msqid的消息队列已被删除 EINTR ——等待消息的情况下,被信号唤醒 EINVAL ——cmd或msqid为无效的参数

EPERM —— 参数cmd为IPC_RMD或IPC_SET ,但调用进程无足

够的权限

3.实例 //sender.c

#include #include #include #include #include #include #include #include

#define MSG_FILE \#define BUFFER 255

#define PERM S_IRUSR|S_IWUSR struct msgbuf {

long mtype;

char mtext[BUFFER+1]; };

char *message[3]= {\ \ \ }; int main() {

struct msgbuf msg; key_t key; int msgid; int i;

if((key=ftok(MSG_FILE,66))==-1) {

fprintf(stderr,\:%s \\n\ exit(EXIT_FAILURE); }

if((msgid=msgget(key,PERM|IPC_CREAT))==-1) {

fprintf(stderr,\:%s \\n\ exit(EXIT_FAILURE); }

msg.mtype=1;

for(i=0; i<3; i++) {

strncpy(msg.mtext,message[i],BUFFER);

msgsnd(msgid,&msg,sizeof(struct msgbuf),0); }

memset(&msg,'\\0',sizeof(struct msgbuf));

msgrcv(msgid,&msg,sizeof(struct msgbuf),2,0); printf(\ if(msgctl(msgid, IPC_RMID, 0) == -1) {

fprintf(stderr, \ exit(EXIT_FAILURE); }

exit(EXIT_SUCCESS); }

//receiver.c

#include #include #include #include #include #include #include #include #include

#define MSG_FILE \#define BUFFER 255

#define PERM S_IRUSR|S_IWUSR struct msgbuf {

long mtype;

char mtext[BUFFER+1]; };

int main() {

struct msgbuf msg; key_t key; int msgid; int i;

char *myask=\ if((key=ftok(MSG_FILE,66))==-1) {

fprintf(stderr,\:%s \\n\ exit(EXIT_FAILURE); }

if((msgid=msgget(key,PERM|IPC_CREAT))==-1) {

fprintf(stderr,\:%s \\n\ exit(EXIT_FAILURE); }

for(i=0; i<3; i++) {

msgrcv(msgid,&msg,sizeof(struct msgbuf),1,0); printf(\ }

msg.mtype=2;

strncpy(msg.mtext,myask,BUFFER);

msgsnd(msgid,&msg,sizeof(struct msgbuf),0);

exit(EXIT_SUCCESS); }

程序的运行结果如下:

上述程序运行时,第三行命令名后的添加的‘&’,可以使命令“./receiver”在后台运行,shell会立即显示命令提示符,等待用户输入下一条命令,再输入“./sender”便可让上述两个程序同时运行。请思考:

(1) 如果不使用后台进程,那应如何运行上述程序,达到进程通信的目的?

(2) 发送给sender的消息、和发送给receiver的消息是存放在相同的消息队列

中,还是存放在各自的消息队列中?

(3) Sender、receiver获取/创建消息队列时使用的键值是否必须相同,如果键值

不同会发生什么情况?

(4) 程序中函数调用msgctl(msgid, IPC_RMID, 0)的目的是什么?如果没有执行该

函数调用,那程序多次运行会不会创建多个消息队列?

<四>编程实现下述功能

1.由父进程创建一个管道,然后再创建2个子进程,并由这两个兄弟进程利用管道进行进程通信:子进程1使用管道的写端,子进程2使用管道的读端。通信的具体内容可根据自己的需要随意设计,要求能试验阻塞型读写过程中的各种情况。运行程序,观察各种情况下,进程实际读写的字节数以及进程阻塞唤醒的情况。

2.编写程序sender,它创建一个消息队列;然后,循环等待用户通过终端输入一串字符,将这串字符通过消息队列发送给receiver,直到用户输入“exit”为止;最后,它向receiver进程发送消息“end”,并且等待receiver的应答,等到应答消息后,将接收到的应答信息显示在终端屏幕上,删除消息队列,结束程序的运行。编写receiver程序,它通过消息队列接收来自sender的消息,将消息显示在终端屏幕上,直至收到内容为“end”的消息为止,此时,它向sender发送一个应答消息“over”,结束程序的运行。

<五> ipcs和ipcrm命令

通过man命令查阅ipcs和ipcrm命令的格式和使用方式,查看目前系统中是否存在消息队列,如果没有,想办法创建若干消息队列,再次使用ipcs查看它们的情况,最后,请将所有的消息队列全部删除。


实验三 - 进程间通信(1)(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:年产砂石总量为4万m3投资建设项目可行性研究报告-广州中撰咨询

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: