《UNIX网络编程 卷2》读书笔记(二)-阿里云开发者社区

开发者社区> 嗯哼9925> 正文

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

简介:
+关注继续查看
 如何知道进程在一个空消息队列中放入一个消息?如果阻塞在msgrcv调用中,则除了等待无法做其他事情,如果给msgrcv指定非阻塞标志(IPC_NOWAIT),尽管不阻塞了,但必须持续调用该函数来确定何时有消息到达,也就是采用轮询方式(polling),Posix消息队列允许异步事件通知来通知何时有消息放入到某个空消息队列中,有2种方式:
1)产生一个信号
2)创建一个线程执行一个指定函数
这通过mq_notify建立。
union sigval
{
   int sival_int;
   void *sival_ptr;
};

struct sigevent
{
   int sigev_notify;
   int sigev_signo;
   union sigval sigev_value;
   void (*sigev_notify_function)(union sigval);
   pthread_attr_t *sigev_notify_attributes;
};


    
#include "unpipc.h"

volatile sig_atomic_t mqflag;
static void sig_usr1(int signo)
{

    mqflag = 1;
    return;
}
int main(int argc,char** argv)
{

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


struct msqid_ds
{
  struct ipc_perm msg_perm;
  struct msg* msg_first;
  struct msg* msg_last;
  msgle_t msg_cbytes;
  msgqnum_t msg_qnum;
  msglen_t  msg_qbytes;
  pid_t msg_lspid;
  pid_t msg_lrpid;
  time_t msg_stime;
  time_t msg_rtime;
  time_t msg_ctime;
};

msgget创建一个新的消息队列或访问一个已经存在的消息队列
msgsnd发送一个消息,消息是下面这样的结构体:
struct msgbuf
{
 long mtype;//消息类型
 char mtext[1];//消息数据
};

 
但这个预定的结构一般无法满足自己的需求,因此一般定义自己的结构
typedef struct my_msgbuf
{
  long mtype;
  int16_t mshort;//消息数据起始
  char mchar[MY_DATA];
}Message;

发送数据时可以指定flag为IPC_NOWAIT,这个标志使得msgsnd调用非阻塞,
 
调用msgrcv函数时,若type指定为0,则返回消息队列第一个消息,若type小于0,则返回类型值小于或等于type绝对值的消息中类型值最小的
第一个消息
 
使用两个消息队列来实现前面的客户—服务器例子,一个队列用于从客户方到服务器的消息,一个队列用于从服务器到客户的消息。

#include "unpipc.h"
#define MQ_KEY1 1234L
#define MQ_KEY2 2345L

int main()
{
    int readid,writeid;
    readid = msgget(MQ_KEY1,SVMSG_MODE|IPC_CREATE);
    writeid = msgget(MQ_KEY2,SVMSG_MODE|IPC_CREATE);
    server(readid,writeid);
    exit(0);
}

int main()
{
    int readid,writeid;
    readid = msgget(MQ_KEY2,0);
    writeid = msgget(MQ_KEY1,0);
    client(readid,writeid);
    //删除消息队列
    msgctl(readid,IPC_RMID,NULL)
    msgctl(writeid,IPC_RMID,NULL);
    exit(0);

}

第8节使用一个队列来实现单服务器,多客户端的通信,但互斥,死锁可能存在,另一种思路就是为每个实体单独设置一个私有队列,消息都发送到自己的队列中,也只从自己的队列中取消息.
System V的消息队列比Posix消息队列差多了,要使用select模型同时处理网络连接和IPC连接时,必须产生子进程,使用管道作为中介,另外一个弱点是无法Peek一个消息.



本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2008/05/27/1208521.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
架构模式-事件驱动架构-调度者拓扑
架构模式 事件驱动架构 调度者拓扑
33 0
从零实现一个日志框架(带源码)
Java里的各种日志框架,相信大家都不陌生。Log4j/Log4j2/Logback/jboss logging等等,其实这些日志框架核心结构没什么区别,只是细节实现上和其性能上有所不同。本文带你从零开始,一步一步的设计一个日志框架
20 0
Kafka无消息丢失配置方案
kafka以其高性能、高吞吐、可扩展等出色能力,被广泛应用在各行各业,是事件流处理平台和消息队列中的佼佼者,但是经常可以看到有人在吐槽kafka消息丢失,但是真的是kafka的锅吗,本文我们就来认真分析一下到底哪些场景可能导致消息丢失以及使用怎么样的方案可以防止消息丢失。
21 0
消息中间件使用规范(RocketMQ)
消息中间件使用规范(RocketMQ)
15 0
Python 知识点总结篇(1)
Python 知识点总结篇(1)
7 0
WIndows下Clion+gcc配置教程
WIndows下Clion+gcc配置教程
31 0
最通俗易懂的Redis发布订阅及代码实战
除了使用List实现简单的消息队列功能以外,Redis还提供了发布订阅的消息机制。在这种机制下,消息发布者向指定频道(channel)发布消息,消息订阅者可以收到指定频道的消息,同一个频道可以有多个消息订阅者,如下图:
11 0
【高并发】为何高并发系统中都要使用消息队列?这次彻底懂了!
很多高并发系统中都会使用到消息队列中间件,那么,问题来了,为什么在高并发系统中都会使用到消息队列中间件呢?立志成为资深架构师的你思考过这个问题吗?
18 0
Python 知识点总结篇(1)
Python 知识点总结篇(1)
11 0
+关注
4716
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载