linux unix 队列,unix/linux 进程间通讯:消息队列

分这么三步吧:

一:创建消息队列

二:向消息队列发送消息

三:从消息队列接收消息

用到的几个主要函数:

1、消息创建函数:

msgget(key_t key,int msgflg);

函数说明:

返回值:如果成功,返回消息队列标识符

如果失败,则返回-1:errno=EACCESS(权限不允许)

EEXIST(队列已经存在,无法创建)

EIDRM(队列标志为删除)

ENOENT(队列不存在)

ENOMEM(创建队列时内存不够)

ENOSPC(超出最大队列限制)

系统调用msgget()中的第一个参数是关键字值(通常是由ftok()返回的)。然后此关键字值将会和其他已经

存在于系统内核中的关键字值比较。这时,打开和存取操作是和参数msgflg中的内容相关的。

IPC_CREAT如果

内核中没有此队列,则创建它。

IPC_EXCL当和IPC_CREAT一起使用时,如果队列已经存在,则失败。

如果单独使用IPC_CREAT,则msgget()要么返回一个新创建的消息队列的标识符,要么返回具有相同关键字

值的队列的标识符。如果IPC_EXCL和IPC_CREAT一起使用,则msgget()要么创建一个新的消息队列,要么如果

队列已经存在则返回一个失败值-1。IPC_EXCL单独使用是没有用处的。

2、消息发送函数:

int msgsnd ( int msqid, struct msgbuf *msgp,

int msgsz, int msgflg );

函数说明:

返回值:

0 :on

success

-1 :on

error: errno = EAGAIN (queue is full, and IPC_NOWAIT was

asserted)

EACCES

(permission denied, no write permission)

EFAULT (msgp

address isn't accessable – invalid)

EIDRM (The

message queue has been removed)

EINTR

(Received a signal while waiting to write)

EINVAL

(Invalid message queue identifier, nonpositive message type, or

invalid message size)

ENOMEM (Not

enough memory to copy message buffer)

传给msgsnd()函数的第一个参数msqid 是消息队列对象的标识符(由msgget()函数得到),第二个参数

msgp

指向要发送的消息所在的内存,第三个参数msgsz 是要发送信息的长度(字节数),可以用以下的公

式计算:

msgsz =

sizeof(struct mymsgbuf) - sizeof(long);

第四个参数是控制函数行为的标志,可以取以下的值:

0,忽略标志位;

IPC_NOWAIT,如果消息队列已满,消息将不被写入队列,控制权返回调用函数的线程。如果不指定这个参

数,线程将被阻塞直到消息被可以被写入。

3、消息接收函数:

int msgrcv

( int msqid, struct msgbuf *msgp, int msgsz, long mtype, int msgflg

);

函数说明:

返回值:接收缓冲区中接收到得消息字节数。

-1 on error: errno = E2BIG

(Message length is greater than msgsz,no MSG_NOERROR)

EACCES (No read

permission)

EFAULT (Address pointed to by

msgp is invalid)

EIDRM (Queue was removed

during retrieval)

EINTR (Interrupted by arriving

signal)

EINVAL (msgqid invalid, or

msgsz less than 0)

ENOMSG (IPC_NOWAIT asserted,

and no message exists in the queue to satisfy the request)

函数的前三个参数和msgsnd()函数中对应的参数的含义是相同的。第四个参数mtype

指定了函数从队列中所取的消息的类型。函数将从队列中搜索类型与之匹配的消息并将之

返回。不过这里有一个例外。如果mtype

的值是零的话,函数将不做类型检查而自动返回

队列中的最旧的消息。

第五个参数依然是是控制函数行为的标志,取值可以是:

0,表示忽略;

IPC_NOWAIT,如果消息队列为空,则返回一个ENOMSG,并将控制权交回调用函数

的进程。如果不指定这个参数,那么进程将被阻塞直到函数可以从队列中得到符合条件的

消息为止。如果一个client 正在等待消息的时候队列被删除,EIDRM 就会被返回。如果进

程在阻塞等待过程中收到了系统的中断信号,EINTR 就会被返回。

MSG_NOERROR,如果函数取得的消息长度大于msgsz,将只返回msgsz 长度的信息,

剩下的部分被丢弃了。如果不指定这个参数,E2BIG 将被返回,而消息则留在队列中不被

取出。

当消息从队列内取出后,相应的消息就从队列中删除了。

下面是一个小例子:

ipc_msg_queue.h 文件

#ifndef PLC_TRAP_H

#define PLC_TRAP_H

typedef struct _trap_message

{

long

msg_type; //存储消息类型

unsigned

char

msg_text[128]; //存储消息内容

}trap_message;

#endif PLC_TRAP_H

ipc_mag_queue.c 文件

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include"plc_trap.h"

static int g_msg_queue_id = 0;

static pthread_t g_msg_rcv_threadTid;

static pthread_t g_msg_snd_threadTid;

static void *msg_send_thread(void *arg)

{

trap_message

msg;

int type = 0;

memset(&msg, 0, sizeof(msg));

printf("send thread enter......\n");

while( 1

)

{

type = random()%5+1;

switch(type)

{

case 1:

strcpy(msg.msg_text,

"AAAAAAAAAA");

break;

case 2:

strcpy(msg.msg_text,

"BBBBBBBBBB");

break;

case 3:

strcpy(msg.msg_text,

"CCCCCCCCCC");

break;

case 4:

strcpy(msg.msg_text,

"DDDDDDDDDD");

break;

case 5:

strcpy(msg.msg_text,

"FFFFFFFFFF");

break;

default:

strcpy(msg.msg_text,

"*******");

break;

}

msg.msg_type = type;

printf("msg type: %d\n", type);

if( (msgsnd(g_msg_queue_id, &msg, sizeof(msg_text),

IPC_NOWAIT)) != 0)

{

printf("send msg

error!\n");

}

else

{

printf("send msg: %s succeed!\n",

msg.msg_text);

}

sleep(1);

}

}

static void *msg_rcv_thread(void *arg)

{

trap_message

msg = {0};

int msg_len

= 0;

printf("manage thread enter......\n");

while( 1

)

{

memset(&msg, 0, sizeof(msg));

msg_len = msgrcv(g_msg_queue_id, &msg,

sizeof(msg_text), 0, IPC_NOWAIT);

if(msg_len < 0)

{

sleep(3);

continue;

}

sleep(2);

printf("recv msg: %s\n", msg.msg_text);

}

}

int main()

{

int fd = -1;

key_t key;

fd =

open("/home/liweiqiang/projects/IPC/msg_queue", O_CREAT, 0660);

if ( -1 == fd )

{

printf("Open msg_queue file

error!\n");

return -1;

}

close(fd);

key =

ftok("/home/liweiqiang/projects/IPC/msg_queue", 't');

if(key == -1) {

printf("init_module ftok

error\n");

return -1 ;

}

if((g_msg_queue_id = msgget(key, IPC_CREAT|0666)) == -1 )

{

printf ("msgget failed

!\n");

return -1;

}

printf("create msg queue succeed......\n");

//创建消息发送线程

if(pthread_create(&g_msg_snd_threadTid,

NULL, msg_send_thread, NULL) != 0)

{

printf("Create msg send manage Thread failed\n");

return -1;

}

//创建消息处理线程

if(pthread_create(&g_msg_rcv_threadTid,

NULL, msg_rcv_thread, NULL) != 0)

{

printf("Create msg rcv Thread

failed\n");

return -1;

}

while ( 1 )

{

sleep(1);

}

return

0;

}

Makefile文件

#!/usr/bin/bash -f

# file: ipc_msg_queue.c

#

====================================================================

# environment definitions;

#

--------------------------------------------------------------------

CFLAGS=-Wall -DMAKEFILE -D__GETOPT_H__ -D_GETOPT_DEFINED_

CC=gcc

BINNAME=msg_queue.exe

OBJ=ipc_msg_queue.o

all:$(OBJ)

$(CC) -o $(BINNAME)

$(OBJ) -lpthread

.PHONY:clean

clean:

rm -rf $(OBJ) $(BINNAME)

make生成msg_queue.exe

运行msg_queue.exe

结果如下:

create msg queue succeed......

manage thread enter......

send thread enter......

msg type: 4

send msg: DDDDDDDDDD succeed!

msg type: 2

send msg: BBBBBBBBBB succeed!

recv msg: FFFFFFFFFF

msg type: 3

send msg: CCCCCCCCCC succeed!

msg type: 1

send msg: AAAAAAAAAA succeed!

recv msg: CCCCCCCCCC

msg type: 4

send msg: DDDDDDDDDD succeed!

msg type: 1

send msg: AAAAAAAAAA succeed!

recv msg: CCCCCCCCCC

msg type: 2

send msg: BBBBBBBBBB succeed!

msg type: 3

send msg: CCCCCCCCCC succeed!

recv msg: DDDDDDDDDD

msg type: 5

send msg: FFFFFFFFFF succeed!

msg type: 2

send msg: BBBBBBBBBB succeed!

recv msg: DDDDDDDDDD

msg type: 3

send msg: CCCCCCCCCC succeed!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值