Chinaunix首页 | 论坛 | 博客
  • 博客访问: 912597
  • 博文数量: 299
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2493
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-21 10:07
个人简介

Linux后台服务器编程。

文章分类

全部博文(299)

文章存档

2015年(2)

2014年(297)

分类: LINUX

2014-07-05 17:39:43

使用信号和管道传递消息存在一定的限制:信号传递的消息有限,管道虽然可以传输一定量的信息,但是只能传递无格式的字节流。3种新的进程间通信(IPC)机制---消息队列、信号量、共享内存,可以解决这些问题。这些机制最早出现在UNIX中,被编入POSIC:XSI中,Linux支持POSIX标准。
 
(1)关于IPC资源
消息队列、信号量、共享内存都是IPC资源,这些资源在使用之前都需要先创建。Linux内核中,IPC资源都可以使用一个非负整数——IPC标识符(消息队列标识符、信号量标识符、共享内存标识符)来进行标识。
 
在创建一个IPC标识符之前,需要指定一个关键字key,可以调用函数ftok()获得。
int ftok(const char *pathname, int prj_id);//失败返回-1
 
(2)关于消息队列
消息队列实际上就是一个链表(工作就是倒腾链表的,从来没倒腾过这种,o(∩_∩)o...),而消息就是链表中具有特定格式和优先级的记录,进程可以根据一定规则在消息链表中添加消息,需要消息的进程则可以从消息队列中获得所需的信息。
 
消息写入消息队列时,系统会将消息加入到消息队列维护的消息链表中。如图所示:
msg_next------|
msg_type       |------>msg_next------|
msg_ts                       msg_type       |------>msg_next
msg_spot|                  msg_ts
                  | -消息      msg_spot---消息
 
msg_next:下一个消息指针
msg_type:消息类型,用户自己定义
msg_ts:消息长度
msg_spot:消息内容
 
(3)消息队列相关函数
1、创建消息队列:int msgget(key_t key,int msgflag)
该函数用于创建或者访问消息队列,获得消息队列标识符符。key就是上面用ftok()获得的IPC关键字。
 
2、获得/修改消息队列属性:int msgctl(int msqid,int cmd,struct msqid_ds *buf);
msqid为要修改、读取属性的消息队列标识符,
参数cmd如果为IPC_STAT时表示读取内核中记录消息队列信息的数据结构msqid_ds,
返回的消息队列属性存放在buf指向的结构体中。
 
3、消息发送:int msgsnd(int msqid,const void *msgp,size_t msgsz,int msgflg);
msqid:要将消息发送的消息队列标识符
msgp:指针指向消息结构体msgbuf
typedef struct {
    long msgtype;  //消息类型,任何大于0的整数,自定义
    char mtext[?]; //消息文本,文本大小由msgsnd中的msgsz决定 
}msgbuf;
msgsz:消息字节数
msgflg:可以为0(忽略该参数)或者IPC_NOWAIT(如果消息队列没有足够空间,如果设置了IPC_NOWAIT,立刻返回;否则函数阻塞,直到等到空间)。
 
4、消息接收:int msgrcv(int msqid,void *msgp,size_t msgsz,long msgtyp,int msgflg);
从msqid代表的消息队列取出消息,存放在msgp指向的缓冲区,缓冲结构定义和发送时使用的msgbuf类似;
msgsz:消息内容长度,msgbuf结构体中mtext的长度;
msgtpye:请求读取的消息类型
msgflg:参数可以取0,也可以取IPC_NOWAIT等。如果为IPC_NOWAIT时,消息队列如果为空,则函数阻塞,直到有消息可以取。
 
(4)实例:
【创建消息队列、发消息】
代码保存systemcall2.c
#include
#include
#include
#include
#include
#define BUF_SIZE 100
typedef struct {
 long mtype;
 char mtext[BUF_SIZE];
}msg_info;   //用于消息发送
//创建消息队列
int creat_msg_queue()
{
 int proj_id = 1;
 int msg_id;
 key_t key;
 
 key = ftok("/home/gaolu",proj_id);  //创建IPC标识符,需要先获得一个key
 if(-1 == key)
 {
  perror("Can't generate the IPC key.\n");
  return -1;
 }
 msg_id = msgget(key,IPC_CREAT|0660); //如果msg_id不存在,则创建,否则,返回已经存在的队列标识符
 if(-1 == msg_id)
 {
  printf("Can't creat message queue resource.\n");
  return -1;
 }
 
 return msg_id;
}
//向队列发消息
int send_msg(int msg_id,char* message)
{
 int result;
 msg_info MsgInfo;
 
 MsgInfo.mtype = 10;  //随意定义,大于0 && 整数 即可
 strcpy(MsgInfo.mtext,message);
 result = msgsnd(msg_id,&MsgInfo,strlen(message),0);
 if(-1 == result)
 {
  perror("Fail to send message to message queue.\n");
 }
 return result;
}
//显示消息信息|验证消息是否发入队列
int show_msg_queue_stat(int msg_id)
{
 struct msqid_ds MsgQueueInfo;
 int result;
 
 result = msgctl(msg_id,IPC_STAT,&MsgQueueInfo); //获得消息队列信息(所有者,权限,消息数……)
 if(-1 == result)
 {
  perror("Can't get status of message queue.\n");
  return -1;
 } 
 printf("======================Message Queue Info=======================\n");
 printf("Effective user id: %d.\n",MsgQueueInfo.msg_perm.uid);
 printf("Effective user group id: %d.\n",MsgQueueInfo.msg_perm.gid);
 printf("Current numbers of bytes in message queue(non-standard): %ld.\n",MsgQueueInfo.__msg_cbytes);
 printf("Current numbers of message in message queue: %ld.\n",MsgQueueInfo.msg_qnum);
 printf("===============================================================\n");
 return 0;
}
int main(void)
{
 int msg_id; 
 int result;
 msg_id = creat_msg_queue();
 send_msg(msg_id,"Test data..............");
 show_msg_queue_stat(msg_id);
 return 0;
}

【取消息】
代码保存msgrcv.c
#include
#include
#include
#include
#include
#define BUF_SIZE 100
typedef struct {
 long mtype;
 char mtext[BUF_SIZE];
}msg_info;
//读取消息队列中指定类型的消息,将消息内容保存在msg指向的地址空间
int rcv_msg(int msg_id,int msg_type,char* msg)
{
 int result;
 msg_info MsgInfo;
 result = msgrcv(msg_id,&MsgInfo,BUF_SIZE,msg_type,0);
 if(-1 == result)
 {
  perror("Can't receive message from message queue.\n");
  return result;
 }
 strcpy(msg,MsgInfo.mtext);
 return result;
}

int main(int argc,char* argv[])
{
 int result;
 char message[BUF_SIZE];
 int msg_type;
 int msg_id;
 if(3 != argc)
 {
  printf("Useage:%s msgid msg_type.\n",argv[0]);
  return -1;
 }
 msg_type = atoi(argv[2]);
 msg_id = atoi(argv[1]);
//获得指定类型消息并显示消息内容
 result = rcv_msg(msg_id,msg_type,message);
 if(-1 == result)
 {
  perror("Fail to receive message.\n");
 }
 else
 {
  printf("Message: %s.\n",message);
 }
 return result; 
}
【执行结果】


 gcc -o msgq systemcall2.c
 gcc -o rcv msgrcv.c
 ./msgq
======================Message Queue Info=======================
Effective user id: 1000.
Effective user group id: 1000.
Current numbers of bytes in message queue(non-standard): 23.
Current numbers of message in message queue: 1.
================================================================

 ipcs -q  //IPC命令 参数q表示消息队列(m:共享内存,s:信号量)
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages   
0x01018b15 0          gaolu      777        23           1          


 ./rcv 0 10        //发消息时消息类型定义为10
Message: Test data...............

阅读(2018) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~