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

时间:2022-08-04 21:06:20

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

1)产生一个信号

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

这通过mq_notify建立。

《UNIX网络编程 卷2》读书笔记(二)union sigval
《UNIX网络编程 卷2》读书笔记(二)《UNIX网络编程 卷2》读书笔记(二)
{
《UNIX网络编程 卷2》读书笔记(二)   
int sival_int;
《UNIX网络编程 卷2》读书笔记(二)   
void *sival_ptr;
《UNIX网络编程 卷2》读书笔记(二)}
;
《UNIX网络编程 卷2》读书笔记(二)
《UNIX网络编程 卷2》读书笔记(二)
struct  sigevent
《UNIX网络编程 卷2》读书笔记(二)《UNIX网络编程 卷2》读书笔记(二)
{
《UNIX网络编程 卷2》读书笔记(二)   
int sigev_notify;
《UNIX网络编程 卷2》读书笔记(二)   
int sigev_signo;
《UNIX网络编程 卷2》读书笔记(二)   union sigval sigev_value;
《UNIX网络编程 卷2》读书笔记(二)   
void (*sigev_notify_function)(union sigval);
《UNIX网络编程 卷2》读书笔记(二)   pthread_attr_t 
*sigev_notify_attributes;
《UNIX网络编程 卷2》读书笔记(二)}
;
《UNIX网络编程 卷2》读书笔记(二)

《UNIX网络编程 卷2》读书笔记(二)    
《UNIX网络编程 卷2》读书笔记(二)#include 
" unpipc.h "
《UNIX网络编程 卷2》读书笔记(二)
《UNIX网络编程 卷2》读书笔记(二)
volatile  sig_atomic_t mqflag;
《UNIX网络编程 卷2》读书笔记(二)
static   void  sig_usr1( int  signo)
《UNIX网络编程 卷2》读书笔记(二)《UNIX网络编程 卷2》读书笔记(二)
{
《UNIX网络编程 卷2》读书笔记(二)
《UNIX网络编程 卷2》读书笔记(二)    mqflag 
= 1;
《UNIX网络编程 卷2》读书笔记(二)    
return;
《UNIX网络编程 卷2》读书笔记(二)}

《UNIX网络编程 卷2》读书笔记(二)
int  main( int  argc, char **  argv)
《UNIX网络编程 卷2》读书笔记(二)《UNIX网络编程 卷2》读书笔记(二)
{
《UNIX网络编程 卷2》读书笔记(二)
《UNIX网络编程 卷2》读书笔记(二)    mqd_t mqd;
《UNIX网络编程 卷2》读书笔记(二)    
void * buff;
《UNIX网络编程 卷2》读书笔记(二)    SSIZE_T n;
《UNIX网络编程 卷2》读书笔记(二)    sigset_t zeromask,newmask,oldmask;
《UNIX网络编程 卷2》读书笔记(二)    
struct mq_attr attr;
《UNIX网络编程 卷2》读书笔记(二)    
struct sigevent sigev;
《UNIX网络编程 卷2》读书笔记(二)    mqd 
= mq_open(argv[1],O_RDONLY|O_NONBLOCK);//打开消息队列
《UNIX网络编程 卷2》读书笔记(二)
    mq_getattr(mqd,&attr);
《UNIX网络编程 卷2》读书笔记(二)    buff 
= malloc(attr.mq_msgsize);//创建接收缓冲区
《UNIX网络编程 卷2》读书笔记(二)
    sigemptyset(&zeromask);
《UNIX网络编程 卷2》读书笔记(二)    sigemptyset(
&newmask);
《UNIX网络编程 卷2》读书笔记(二)    sigemptyset(
&oldmask);
《UNIX网络编程 卷2》读书笔记(二)    sigaddset(
&newmask,SIGUSR1);
《UNIX网络编程 卷2》读书笔记(二)    
//初始化信号处理
《UNIX网络编程 卷2》读书笔记(二)
    signal(SIGUSR1,sig_usr1);
《UNIX网络编程 卷2》读书笔记(二)    sigev.sigev_notify 
= SIGEV_SIGNAL;
《UNIX网络编程 卷2》读书笔记(二)    sigev.sigev_signo 
= SIGUSR1;
《UNIX网络编程 卷2》读书笔记(二)    mq_notify(mqd,
&sigev);
《UNIX网络编程 卷2》读书笔记(二)    
for(;;)
《UNIX网络编程 卷2》读书笔记(二)《UNIX网络编程 卷2》读书笔记(二)    
{
《UNIX网络编程 卷2》读书笔记(二)        sigprocmask(SIG_BLOCK,
&newmask,&oldmask);//阻塞SIGUSR1信号
《UNIX网络编程 卷2》读书笔记(二)
        while(mqflag==0)sigsuspend(&zeromask);
《UNIX网络编程 卷2》读书笔记(二)        mqflag 
= 0;
《UNIX网络编程 卷2》读书笔记(二)        mq_notify(mqd,
&sigev);
《UNIX网络编程 卷2》读书笔记(二)        
while((n=mq_receive(mqd,buff,attr.mq_msgsize,NULL))>=0)
《UNIX网络编程 卷2》读书笔记(二)《UNIX网络编程 卷2》读书笔记(二)        
{//循环接收数据
《UNIX网络编程 卷2》读书笔记(二)
            printf("read %ld bytes\n",(long)n);
《UNIX网络编程 卷2》读书笔记(二)        }

《UNIX网络编程 卷2》读书笔记(二)        sigprocmask(SIG_UNBLOCK,
&newmask,NULL);
《UNIX网络编程 卷2》读书笔记(二)    }

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

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

《UNIX网络编程 卷2》读书笔记(二)struct  msqid_ds
《UNIX网络编程 卷2》读书笔记(二)《UNIX网络编程 卷2》读书笔记(二)
{
《UNIX网络编程 卷2》读书笔记(二)  
struct ipc_perm msg_perm;
《UNIX网络编程 卷2》读书笔记(二)  
struct msg* msg_first;
《UNIX网络编程 卷2》读书笔记(二)  
struct msg* msg_last;
《UNIX网络编程 卷2》读书笔记(二)  msgle_t msg_cbytes;
《UNIX网络编程 卷2》读书笔记(二)  msgqnum_t msg_qnum;
《UNIX网络编程 卷2》读书笔记(二)  msglen_t  msg_qbytes;
《UNIX网络编程 卷2》读书笔记(二)  pid_t msg_lspid;
《UNIX网络编程 卷2》读书笔记(二)  pid_t msg_lrpid;
《UNIX网络编程 卷2》读书笔记(二)  time_t msg_stime;
《UNIX网络编程 卷2》读书笔记(二)  time_t msg_rtime;
《UNIX网络编程 卷2》读书笔记(二)  time_t msg_ctime;
《UNIX网络编程 卷2》读书笔记(二)}
;
《UNIX网络编程 卷2》读书笔记(二)

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

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

《UNIX网络编程 卷2》读书笔记(二)struct  msgbuf
《UNIX网络编程 卷2》读书笔记(二)《UNIX网络编程 卷2》读书笔记(二)
{
《UNIX网络编程 卷2》读书笔记(二) 
long mtype;//消息类型
《UNIX网络编程 卷2》读书笔记(二)
 char mtext[1];//消息数据
《UNIX网络编程 卷2》读书笔记(二)
}
;
《UNIX网络编程 卷2》读书笔记(二)

 

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

《UNIX网络编程 卷2》读书笔记(二)typedef  struct  my_msgbuf
《UNIX网络编程 卷2》读书笔记(二)《UNIX网络编程 卷2》读书笔记(二)
{
《UNIX网络编程 卷2》读书笔记(二)  
long mtype;
《UNIX网络编程 卷2》读书笔记(二)  int16_t mshort;
//消息数据起始
《UNIX网络编程 卷2》读书笔记(二)
  char mchar[MY_DATA];
《UNIX网络编程 卷2》读书笔记(二)}
Message;
《UNIX网络编程 卷2》读书笔记(二)

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

 

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

第一个消息

 

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

《UNIX网络编程 卷2》读书笔记(二)
《UNIX网络编程 卷2》读书笔记(二)#include 
" unpipc.h "
《UNIX网络编程 卷2》读书笔记(二)
#define  MQ_KEY1 1234L
《UNIX网络编程 卷2》读书笔记(二)
#define  MQ_KEY2 2345L
《UNIX网络编程 卷2》读书笔记(二)
《UNIX网络编程 卷2》读书笔记(二)
int  main()
《UNIX网络编程 卷2》读书笔记(二)《UNIX网络编程 卷2》读书笔记(二)
{
《UNIX网络编程 卷2》读书笔记(二)    
int readid,writeid;
《UNIX网络编程 卷2》读书笔记(二)    readid 
= msgget(MQ_KEY1,SVMSG_MODE|IPC_CREATE);
《UNIX网络编程 卷2》读书笔记(二)    writeid 
= msgget(MQ_KEY2,SVMSG_MODE|IPC_CREATE);
《UNIX网络编程 卷2》读书笔记(二)    server(readid,writeid);
《UNIX网络编程 卷2》读书笔记(二)    exit(
0);
《UNIX网络编程 卷2》读书笔记(二)}

《UNIX网络编程 卷2》读书笔记(二)
《UNIX网络编程 卷2》读书笔记(二)
int  main()
《UNIX网络编程 卷2》读书笔记(二)《UNIX网络编程 卷2》读书笔记(二)
{
《UNIX网络编程 卷2》读书笔记(二)    
int readid,writeid;
《UNIX网络编程 卷2》读书笔记(二)    readid 
= msgget(MQ_KEY2,0);
《UNIX网络编程 卷2》读书笔记(二)    writeid 
= msgget(MQ_KEY1,0);
《UNIX网络编程 卷2》读书笔记(二)    client(readid,writeid);
《UNIX网络编程 卷2》读书笔记(二)    
//删除消息队列
《UNIX网络编程 卷2》读书笔记(二)
    msgctl(readid,IPC_RMID,NULL)
《UNIX网络编程 卷2》读书笔记(二)    msgctl(writeid,IPC_RMID,NULL);
《UNIX网络编程 卷2》读书笔记(二)    exit(
0);
《UNIX网络编程 卷2》读书笔记(二)
《UNIX网络编程 卷2》读书笔记(二)}

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

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

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