实验三2Linux进程间通信Word下载.docx
《实验三2Linux进程间通信Word下载.docx》由会员分享,可在线阅读,更多相关《实验三2Linux进程间通信Word下载.docx(7页珍藏版)》请在冰豆网上搜索。
msgget()建立一个消息队列;
msgctl()操纵一个消息队列;
msgsnd()发送消息;
msgrcv()接收消息;
signal()设置对信号的处理方式或处理过程;
pipe()打开管道;
lockf()锁定一个文件。
(二)使用共享存储区的示例程序
下面程序主要用来演示共享存储区的使用方法:
首先要使用shmget得到共享存储区句柄(可以新建或连接已有的共享存储区,以关键字标识),然后使用shmat挂接到进程的存储空间(这样才能够访问),当使用完后,使用shmctl释放(shmctl还可以完成一些其他功能)。
这种使用逻辑也适用于消息和信号量。
示例程序代码如下:
#include<
sys/types.h>
unistd.h>
stdio.h>
sys/ipc.h>
sys/shm.h>
intmain(void)
{
intx,shmid;
int*shmptr;
if((shmid=shmget(IPC_PRIVATE,sizeof(int),IPC_CREAT|0666))<
0)
printf("
shmgeterror"
),exit
(1);
//函数原型intshmget(key_tkey,intsize,intshmflg);
函数用于创建(或者获取)一
key键值指定的共享内存对象,返回该对象的系统标识符:
shmid;
size是创个由
IPC_CREAT|0666,说明新建一个权限为0666的消息队列,建的共享内存的大小,
id,若其中组用户、当前用户以及其他用户拥有读写的权限若成功则返回共享内存
-1出错则为
if((shmptr=(int*)shmat(shmid,0,0))==(int*)-1)
shmaterror"
//void*shmat(intshm_id,void*shm_addr,intshmflg);
shm_id标识码,shm_addr连
shmflg标志位接到的地址
Inputainitialvaluefor*shmptr:
"
);
scanf("
%d"
shmptr);
while((x=fork())==-1);
if(x==0)/*childrun*/
Whenchildruns,*shmptr=%d\n"
*shmptr);
Inputavalueinchild:
*shmptr=%d\n"
}
else/*parentrun*/
wait();
Afterchildruns,inparent,*shmptr=%d\n"
if(shmctl(shmid,IPC_RMID,0)<
0)
//shmctl()函数声明:
intshmctl(intshmqid,intcmd,structshmid_ds*buf);
返回值:
0onsuccess
函数用于对已创建的共享内存对象进行查询、设值、删除等操作;
这个函数-1onerror:
和msgget()函数十分相似,用法也相同。
它支持的操作有:
shm_id所指向内存共享段的shmid_dsIPC_STAT获得共享内存的信息,
结构,对参数buf指向的结构。
使用buf指向的结构对sh_mid段的相关结IPC_SET设定共享内存的信息,
构赋值,只对以下几个域有作用,shm_perm.
uidshm_perm.gid以及shm_perm.mode
注意此命令只有具备以下条件的进程才可以请求:
1(进程的用户ID等于shm_perm.cuid或者
等于shm_perm.uid
2(超级用户特权进程。
删除shm_id所指向的共享内存段,只有当IPC_RMID删除共享内存,
shmid_ds结构的shm_nattch域为零时,才
会真正执行删除命令,否则不会删除该段注意此命令的请求规则与IPC_SET命令相同。
需要说明的是,当执行IPC_RMID操作时,系统并不是立即将其删除,而只是将其标为待删,然后等待与其连接的进程断开连接。
只有当所有的连接都断开以后系统才执行真正的删除操
作。
当然,如果执行IPC_RMID的时候没有任何的连接,删除将是立即的。
shmctlerror"
(三)使用消息机制的示例程序
示例程序执行的进程分为两种,分别称为服务进程和客户进程:
服务进程只有一个,接收各客户进程以消息形式发出的问题,接收键盘输入作为回答,再以消息形式送给提问的进程。
各客户进程接收键盘输入作为问题,以消息形式发给服务进程,等待接收服务进程发来的回答消息,再开始下一轮的循环。
示例程序的实际执行效果如下:
编译后执行,第一个进程实例将作为服务进程,提示:
ACTSERVER!
!
Waitquestionandgiveanswer.
Toendthisprocess,tryCtrl+Corusekill.
服务进程一直循环执行,直到用户按Ctrl+C终止执行,或使用kill命令杀死服务进程。
其他进程实例作为客户进程,提示:
Actasclient,askquestionandwaitanswer!
Toendthisprocess,enterendasinputquestion.
客户进程一直循环执行,直到用户输入end。
示例程序的代码如下:
signal.h>
string.h>
sys/msg.h>
#defineMY_KEY10071140//needtochange
#defineSERVER_ID2
#defineMAX_BUF200
voidsigend(int);
structmymsg{
longmtype;
longpid;
charbuf[MAX_BUF];
};
intmsgid;
structmymsgmsgbuf;
if((msgid=msgget(MY_KEY,IPC_CREAT|IPC_EXCL|0666))<
//intmsgget(key_tkey,intflags);
函数中参数key用来转换成一个标识符,每一
IPC对象与一个key相对应。
参数flags标明函数的行为,函数中参数falgs指定个
IPC_CREAT|0666,说明新建一个权限为0666的消息队列,其中组用户、当前用为
户以及其他用户拥有读写的权限
{/*messagequeueexists,actasclient*/
msgid=msgget(MY_KEY,0666);
\n"
Toendthisprocess,enterendasinputquestion.\n\n"
Inputquestioninoneline:
fgets(msgbuf.buf,sizeof(structmymsg)-2*sizeof(long)-1,stdin);
//fgets:
从流中读取一字符串,char*fgets(char*string,intn,FILE*stream);
形参注释:
*string结果数据的首地址;
n-1:
一次读入数据块的长度,其默认值为1k,
1024;
stream文件指针即
while(strcmp(msgbuf.buf,"
end\n"
))
msgbuf.mtype=SERVER_ID;
msgbuf.pid=getpid();
msgsnd(msgid,&
msgbuf,sizeof(structmymsg)-sizeof(long),0);
//新的消息总是放在队列的尾部,函数中参数msqid指定要操作的队列,struct
msgbuf{
charmbuf[];
mbuf是一个字符数组,长度是根据具体的消息来决定的,切忌消息不能以NULL
结尾。
成员mtype是消息的类型字段。
函数参数nbytes指定了消息的长度,参数flags
指明函数的行为。
函数成功返回0,失败返回-1并设置错误变量errno。
msgrcv(msgid,&
msgbuf,sizeof(structmymsg),getpid(),0);
//msgrcv(intmsqid,void*ptr,size_tnbytes,longtype,intflag);
函数中参数
msqid为指定要读的队列,参数ptr为要接收数据的缓冲区,nbytes为要接收数据的
nbytes的值时,则会参照行为参数flag的长度,当队列中满足条件的消息长度大于
flag中设置了MSG_NOERROR位时,则将消息截短到nbytes值决定如何操作:
当
指定的长度后返回。
Answerfromserver:
\n%s"
msgbuf.buf);
else/*actsasserver*/
signal(SIGINT,sigend);
//如果发生SIGINT信号则中断,转去执行sig