《UNIX网络编程 卷2》读书笔记(二)

如何知道进程在一个空消息队列中放入一个消息?如果阻塞在msgrcv调用中,则除了等待无法做其他事情,如果给msgrcv指定非阻塞标志(IPC_NOWAIT),尽管不阻塞了,但必须持续调用该函数来确定何时有消息到达,也就是采用轮询方式(polling),Posix消息队列允许异步事件通知来通知何时有消息放入到某个空消息队列中,有2种方式:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

1)产生一个信号

2)创建一个线程执行一个指定函数

这通过mq_notify建立。

None.gif unionsigval
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
intsival_int;
InBlock.gif
void*sival_ptr;
ExpandedBlockEnd.gif}
;
None.gif
None.gif
struct sigevent
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
intsigev_notify;
InBlock.gif
intsigev_signo;
InBlock.gifunionsigvalsigev_value;
InBlock.gif
void(*sigev_notify_function)(unionsigval);
InBlock.gifpthread_attr_t
*sigev_notify_attributes;
ExpandedBlockEnd.gif}
;
None.gif

None.gif
None.gif#include
" unpipc.h "
None.gif
None.gif
volatile sig_atomic_tmqflag;
None.gif
static void sig_usr1( int signo)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
InBlock.gifmqflag
=1;
InBlock.gif
return;
ExpandedBlockEnd.gif}

None.gif
int main( int argc, char ** argv)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
InBlock.gifmqd_tmqd;
InBlock.gif
void*buff;
InBlock.gifSSIZE_Tn;
InBlock.gifsigset_tzeromask,newmask,oldmask;
InBlock.gif
structmq_attrattr;
InBlock.gif
structsigeventsigev;
InBlock.gifmqd
=mq_open(argv[1],O_RDONLY|O_NONBLOCK);//打开消息队列
InBlock.gif
mq_getattr(mqd,&attr);
InBlock.gifbuff
=malloc(attr.mq_msgsize);//创建接收缓冲区
InBlock.gif
sigemptyset(&zeromask);
InBlock.gifsigemptyset(
&newmask);
InBlock.gifsigemptyset(
&oldmask);
InBlock.gifsigaddset(
&newmask,SIGUSR1);
InBlock.gif
//初始化信号处理
InBlock.gif
signal(SIGUSR1,sig_usr1);
InBlock.gifsigev.sigev_notify
=SIGEV_SIGNAL;
InBlock.gifsigev.sigev_signo
=SIGUSR1;
InBlock.gifmq_notify(mqd,
&sigev);
InBlock.gif
for(;;)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifsigprocmask(SIG_BLOCK,
&newmask,&oldmask);//阻塞SIGUSR1信号
InBlock.gif
while(mqflag==0)sigsuspend(&zeromask);
InBlock.gifmqflag
=0;
InBlock.gifmq_notify(mqd,
&sigev);
InBlock.gif
while((n=mq_receive(mqd,buff,attr.mq_msgsize,NULL))>=0)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{//循环接收数据
InBlock.gif
printf("read%ldbytes/n",(long)n);
ExpandedSubBlockEnd.gif}

InBlock.gifsigprocmask(SIG_UNBLOCK,
&newmask,NULL);
ExpandedSubBlockEnd.gif}

InBlock.gifexit(
0);
InBlock.gif
ExpandedBlockEnd.gif}

None.gif

None.gif struct msqid_ds
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
structipc_permmsg_perm;
InBlock.gif
structmsg*msg_first;
InBlock.gif
structmsg*msg_last;
InBlock.gifmsgle_tmsg_cbytes;
InBlock.gifmsgqnum_tmsg_qnum;
InBlock.gifmsglen_tmsg_qbytes;
InBlock.gifpid_tmsg_lspid;
InBlock.gifpid_tmsg_lrpid;
InBlock.giftime_tmsg_stime;
InBlock.giftime_tmsg_rtime;
InBlock.giftime_tmsg_ctime;
ExpandedBlockEnd.gif}
;
None.gif

msgget创建一个新的消息队列或访问一个已经存在的消息队列

msgsnd发送一个消息,消息是下面这样的结构体:

None.gif struct msgbuf
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
longmtype;//消息类型
InBlock.gif
charmtext[1];//消息数据
ExpandedBlockEnd.gif
}
;
None.gif

但这个预定的结构一般无法满足自己的需求,因此一般定义自己的结构

None.gif typedef struct my_msgbuf
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
longmtype;
InBlock.gifint16_tmshort;
//消息数据起始
InBlock.gif
charmchar[MY_DATA];
ExpandedBlockEnd.gif}
Message;
None.gif

发送数据时可以指定flagIPC_NOWAIT,这个标志使得msgsnd调用非阻塞,

调用msgrcv函数时,若type指定为0,则返回消息队列第一个消息,若type小于0,则返回类型值小于或等于type绝对值的消息中类型值最小的

第一个消息

使用两个消息队列来实现前面的客户服务器例子,一个队列用于从客户方到服务器的消息,一个队列用于从服务器到客户的消息。

None.gif
None.gif#include
" unpipc.h "
None.gif
#define MQ_KEY11234L
None.gif
#define MQ_KEY22345L
None.gif
None.gif
int main()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
intreadid,writeid;
InBlock.gifreadid
=msgget(MQ_KEY1,SVMSG_MODE|IPC_CREATE);
InBlock.gifwriteid
=msgget(MQ_KEY2,SVMSG_MODE|IPC_CREATE);
InBlock.gifserver(readid,writeid);
InBlock.gifexit(
0);
ExpandedBlockEnd.gif}

None.gif
None.gif
int main()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
intreadid,writeid;
InBlock.gifreadid
=msgget(MQ_KEY2,0);
InBlock.gifwriteid
=msgget(MQ_KEY1,0);
InBlock.gifclient(readid,writeid);
InBlock.gif
//删除消息队列
InBlock.gif
msgctl(readid,IPC_RMID,NULL)
InBlock.gifmsgctl(writeid,IPC_RMID,NULL);
InBlock.gifexit(
0);
InBlock.gif
ExpandedBlockEnd.gif}

None.gif

8节使用一个队列来实现单服务器,多客户端的通信,但互斥,死锁可能存在,另一种思路就是为每个实体单独设置一个私有队列,消息都发送到自己的队列中,也只从自己的队列中取消息.

System V的消息队列比Posix消息队列差多了,要使用select模型同时处理网络连接和IPC连接时,必须产生子进程,使用管道作为中介,另外一个弱点是无法Peek一个消息.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值