Linux消息队列之命令行相关

一、消息队列 

(也叫做报文队列)是Unix系统V版本中3种进程间通信机制之一。另外两种是信号灯和共享内存。这些IPC机制使用共同的授权方法。只有通过系统调用将标志符传递给核心之后,进程才能存取这些资源。这种系统IPC对象使用的控制方法和文件系统非常类似。使用对象的引用标志符作为资源表中的索引。

消息队列就是一个消息的链表。就是把消息看作一个记录,并且这个记录具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读出消息。

Linux采用消息队列的方式来实现消息传递。这种消息的发送方式是:发送方不必等待接收方检查它所收到的消息就可以继续工作下去,而接收方如果没有收到消息也不需等待。这种通信机制相对简单,但是应用程序使用起来就需要使用相对复杂的方式来应付了。新的消息总是放在队列的末尾,接收的时候并不总是从头来接收,可以从中间来接收。

消息队列是随内核持续的并和进程相关,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除。因此系统中记录消息队列的数据结构 (struct ipc_ids msg_ids)位于内核中,系统中的所有消息队列都可以在结构msg_ids中中找到访问入口。

IPC标识符:每一个I P C目标都有一个唯一的I P C标识符。这里所指的I P C目标是指一个单独的消息队列、一个信号量集或者一个共享的内存段。系统内核使用此标识符在系统内核中指明 I P C目标。

IPC 关键字:想要获得唯一的标识符,则必须使用一个 I P C关键字。客户端进程和服务器端进程必须双方都同意此关键字。这是建立一个客户机/服务器框架的第一步。在System V IPC机制中,建立两端联系的路由方法是和I P C关键字直接相关的。通过在应用程序中设置关键字值,每一次使用的关键字都可以是相同的。一般情况下,可以使用f t o k ( )函数为客户端和服务器端产生关键字值。

二、ipcs 命令

命令ipcs用于读取System V IPC目标的状态。


[elink@localhost debug]$ ipcs

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status     
0xe24a5000 1409027    elink      600        24         1                      
0xe24a6000 1114116    elink      600        419432856  37                     

------ Semaphore Arrays --------
key        semid      owner      perms      nsems    
0xe20a2000 557067     elink      600        100      

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages   
0xe24a0100 851968     elink      600        0            0          
0xe24a283c 884737     elink      600        0            0          
0xe24a283d 917506     elink      600        0            0          
0xe24a2838 950275     elink      600        0            0          
0xe24a2839 2293764    elink      600        0            0          
0xa4000501 1015813    elink      600        0            0          
0xa4000601 1048582    elink      600        0            0          
0xe24a2438 1081351    elink      600        0            0          
0xe24a2439 1114120    elink      600        0            0          
0xe24a243a 1146889    elink      600        0            0          
0xe24a243b 1179658    elink      600        0            0          
0xe24a4378 1212427    elink      600        0            0          
0xe24a4379 1245196    elink      600        0            0          
0xe24a46fc 1277965    elink      600        0            0          
0xe24a46fd 1310734    elink      600        0            0          
0xe24a25c8 1343503    elink      600        0            0          
0xe24a25c9 1376272    elink      600        0            0          
0xe24a262c 1409041    elink      600        0            0          
0xe24a262d 1441810    elink      600        0            0          
0xe24a2c08 1474579    elink      600        0            0          
0xe24a2c09 1507348    elink      600        0            0          
0xe24a243c 1540117    elink      600        0            0          
0xe24a243d 1572886    elink      600        0            0          
0xe24a46fe 1835031    elink      600        0            0          
0xe24a46ff 1867800    elink      600        0            0          
0x0a30a68c 1966105    elink      660        0            0          
0x85eb568c 1998874    elink      660        0            0          
0xd327768c 2031643    elink      660        0            0          
0x7a8c768c 2064412    elink      660        0            0          
0xea43668c 2097181    elink      660        0            0          
0x3076f68c 2162718    elink      660        0            0          
0x7537668c 2195487    elink      660        0            0          
0xa557768c 2228256    elink      660        0            0          
0x87f0468c 2261025    elink      660        0            0          

[elink@localhost debug]$ netstat -an|grep 50001
tcp        0      0 192.168.17.10:64206         222.66.233.201:50001        ESTABLISHED
[elink@localhost debug]$ ipcs

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status     
0xe24a5000 1409027    elink      600        24         1                      
0xe24a6000 1114116    elink      600        419432856  47                     

------ Semaphore Arrays --------
key        semid      owner      perms      nsems    
0xe20a2000 557067     elink      600        100      

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages   
0xe24a0100 851968     elink      600        0            0          
0xe24a283c 884737     elink      600        0            0          
0xe24a283d 917506     elink      600        0            0          
0xe24a2838 950275     elink      600        0            0          
0xe24a2839 2293764    elink      600        0            0          
0xa4000501 1015813    elink      600        0            0          
0xa4000601 1048582    elink      600        0            0          
0xe24a2438 1081351    elink      600        0            0          
0xe24a2439 1114120    elink      600        0            0          
0xe24a243a 1146889    elink      600        0            0          
0xe24a243b 1179658    elink      600        0            0          
0xe24a4378 1212427    elink      600        0            0          
0xe24a4379 1245196    elink      600        0            0          
0xe24a46fc 1277965    elink      600        0            0          
0xe24a46fd 1310734    elink      600        0            0          
0xe24a25c8 1343503    elink      600        0            0          
0xe24a25c9 1376272    elink      600        0            0          
0xe24a262c 1409041    elink      600        0            0          
0xe24a262d 1441810    elink      600        0            0          
0xe24a2c08 1474579    elink      600        0            0          
0xe24a2c09 1507348    elink      600        0            0          
0xe24a243c 1540117    elink      600        0            0          
0xe24a243d 1572886    elink      600        0            0          
0xe24a46fe 1835031    elink      600        0            0          
0xe24a46ff 1867800    elink      600        0            0          
0x0a30a68c 1966105    elink      660        0            0          
0x85eb568c 1998874    elink      660        0            0          
0xd327768c 2031643    elink      660        0            0          
0x7a8c768c 2064412    elink      660        0            0          
0xea43668c 2097181    elink      660        0            0          
0x3076f68c 2162718    elink      660        0            0          
0x7537668c 2195487    elink      660        0            0          
0xa557768c 2228256    elink      660        0            0          
0x87f0468c 2261025    elink      660        0            0          
0xffffe6e9 2326562    elink      660        0            0          
0x00000039 2359331    elink      660        0            0          

三、消息队列的主要调用

内核中实现消息传递机制的代码基本上都在文件ipc/msg.c中,消息队列的主要调用有下面4个,这里只作简单介绍:

(1)msgget:调用者提供一个消息队列的键标 (用于表示个消息队列的唯一名字),当这个消息队列存在的时候, 这个消息调用负责返回这个队列的标识号;如果这个队列不存在,就创建一个消息队列,然后返回这个消息队列的标识号 ,主要由sys_msgget执行。

(2)msgsnd:向一个消息队列发送一个消息,主要由sys_msgsnd执行。

(3)msgrcv:从一个消息队列中收到一个消息,主要由sys_msgrcv执行。

(4)msgctl:在消息队列上执行指定的操作。根据参数的不同和权限的不同,可以执行检索、删除等的操作,主要由sys_msgctl执行。

四、消息队列的应用例子

下面的例子很好的演示了创建、发送、读取、改变权限以及删除消息队列各种操作:

 

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define MAX_SEND_SIZE 2000

struct mymsgbuf {
	long mtype;
	char mtext[MAX_SEND_SIZE];
};

void send_message(int qid, struct mymsgbuf *qbuf, long type, char *text);
void read_message(int qid, struct mymsgbuf *qbuf, long type);
void remove_queue(int qid);
void change_queue_mode(int qid, char *mode);
void usage(void);

/**
*执行举例:./ipcs r 1998 104
*入参:
*			argv[1]		'r' or 's' or 'm' or 'd'
*			argv[2]		消息队列id
*			argv[3]		mtype
*			argv[4]		msg_content(仅当要发送消息时使用)
*/
int main(int argc, char *argv[])
{
	//key_t key;
	int msgqueue_id;
	struct mymsgbuf qbuf;

	if(argc == 1)
		usage();

#if 0
	/* Create unique key via call to ftok() */
	key = ftok(".", 'm');/*m=ox(6D)*/
#endif

	/* Open the queue - create if necessary */
	if((msgqueue_id = msgget(*argv[2], IPC_CREAT|0660)) == -1)

	{
		perror("msgget error\n");
		exit(1);
	}else{
		printf("msgget success\n");
	}
	
	printf("you choose :%d\n",tolower(*argv[1]));
	
	switch(tolower(*argv[1]))
	{
		case 's': send_message(msgqueue_id, (struct mymsgbuf *)&qbuf,atol(argv[3]), argv[4]);
		break;
		case 'r': read_message(msgqueue_id, &qbuf, atol(argv[2]));
		break;
		case 'd': remove_queue(msgqueue_id);
		break;
		case 'm': change_queue_mode(msgqueue_id, argv[2]);
		break;

		default: usage();

	}

	return(0);
	}

void send_message(int qid, struct mymsgbuf *qbuf, long type, char *text)
{
	/* Send a message to the queue */
	printf("Sending a message!\n");
	qbuf->mtype = type;
	strcpy(qbuf->mtext, text);

	if((msgsnd(qid, (struct msgbuf *)qbuf,strlen(qbuf->mtext)+1, 0)) ==-1)
	{
	perror("msgsnd");
	exit(1);
	}
}

void read_message(int qid, struct mymsgbuf *qbuf, long type)
{
	/* Read a message from the queue */
	printf("Reading a message!\n");
	qbuf->mtype = type;
	msgrcv(qid, (struct msgbuf *)qbuf, MAX_SEND_SIZE, type, 0);

	printf("Type: %ld\n", qbuf->mtype);
	printf("Text: %sn\n",qbuf->mtext);
}

void remove_queue(int qid)
{
	/* Remove the queue */
	msgctl(qid, IPC_RMID, 0);
}

void change_queue_mode(int qid, char *mode)
{
	struct msqid_ds myqueue_ds;

	/* Get current info */
	msgctl(qid, IPC_STAT, &myqueue_ds);

	/* Convert and load the mode */
	sscanf(mode, "%ho", &myqueue_ds.msg_perm.mode);

	/* Update the mode */
	msgctl(qid, IPC_SET, &myqueue_ds);
}

void usage(void)
{
	fprintf(stderr, "msgtool - A utility for tinkering with msg queuesn\n");
	fprintf(stderr, "nUSAGE: msgtool\n");
	fprintf(stderr, "(s)end \n");
	fprintf(stderr, " (r)ecv\n");
	fprintf(stderr, " (d)elete\n");
	fprintf(stderr, " (m)ode \n");
	exit(1);
}



程序保存为 ipcs.c

编译:gcc -o ipcs ipcs.c

 


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include #include #include "vxWorks.h" #include "msgQLib.h" #include "taskLib.h" /*#include "memPartLib.h"*/ #include "memLib.h" /*宏定义*/ #define MAX_MSGS (10) /* the length of msg*/ #define MAX_MSG_LEN sizeof(MESSAGE) /*the length of message*/ #define STACK_SIZE 20000 /*the stack size of task*/ #define DELAY_TICKS 50 /*the time of sending message*/ #define MAX_point 5 /*用户从系统内存池中获得内存的最大次数*/ #define size_1 30 /*用户分区的分配的大小*/ #define size_2 40 /*全局变量*/ int tidtask1; int tidtask2; int tidtask3; SEM_ID syncSemId; SEM_ID waitSemId; MSG_Q_ID myMsgQId1; MSG_Q_ID myMsgQId2; MSG_Q_ID myMsgQId3; typedef struct _MESSAGE { int mSendId; /*发送任务 ID*/ int mRecvId; /*接收任务 ID*/ int mData; /*消息中传递的数据*/ char Data[14]; } MESSAGE; /*内存管理*/ char* usermem1; char* usermem2; MESSAGE *point1[MAX_point]; MESSAGE *point2[MAX_point]; MESSAGE *point3[MAX_point]; int point1_index=0; int point2_index=0; int point3_index=0; PART_ID partid1; PART_ID partid2; #define MID_MESSAGE(id) (id) /*函数声明*/ int start(void); int task1(void); int task2(void); int task3(void); template T* mymalloc(unsigned nBytes); void myfree(void); void bye(void); /***************************************[progStart]*******************************************/ /*启动程序,创建息队例,任务*/ int start(void) { tidtask1=taskSpawn("tTask1", 220, 0, STACK_SIZE, (FUNCPTR)task1,0,0,0,0,0,0,0,0,0,0); usermem1=malloc(200); partid1=memPartCreate(usermem1,200); usermem2=malloc(400); partid2=memPartCreate(usermem2,400); return; } /**************************************[test_end]********************************************/ /*是否相等,相等返回1*/ int test_end(char *end,char *target) { int ret; if(!strcmp(end,target)) ret=1; else ret=0; return ret; } /****************************************[task1]***********************************************/ /*管理Task。负责系统启动时同步系统中其他Task的启动同步,利用信号量的semFlush()完成。同时接收各*/ /*Task的告警信息,告警信息需编号以logmsg方式输出。本task负责系统结束时的Task删除处理*/ int task1(void) { int singal; int message; MESSAGE *rxMsg=mymalloc(26); /*define messages,and alloc memory*/ memset(rxMsg,0,26); syncSemId=semBCreate(SEM_Q_FIFO,SEM_EMPTY); /*creat semaphore*/ waitSemId=semBCreate(SEM_Q_PRIORITY,SEM_EMPTY); myMsgQId1=msgQCreate(MAX_MSGS,MAX_MSG_LEN,MSG_Q_PRIORITY); /*create msgQ*/ myMsgQId2=msgQCreate(MAX_MSGS,MAX_MSG_LEN,MSG_Q_PRIORITY); myMsgQId3=msgQCreate(MAX_MSGS,MAX_MSG_LEN,MSG_Q_PRIORITY); tidtask2=taskSpawn("tTask2", 200, 0, STACK_SIZE, (FUNCPTR)task2,0,0,0,0,0,0,0,0,0,0); /*create task*/ tidtask3=taskSpawn("tTask3", 210, 0, STACK_SIZE, (FUNCPTR)task3,0,0,0,0,0,0,0,0,0,0); printf("Please input one of the following commands:add,sub,multiply,divide,testcommand\n"); /*the command we should put into the console*/ semFlush(syncSemId); /*release semaphore*/ semGive(waitSemId); while(1) { singal=1; msgQReceive(myMsgQId1,(char*)&rxMsg,sizeof(rxMsg),WAIT_FOREVER); if(rxMsg->mRecvId==MID_MESSAGE(3)) /*receive MsgQ from task3*/ { singal=test_end(rxMsg->Data,"wrong length")-1; logMsg("task3 receiveing a:%s\n",rxMsg->Data); /*put the warn from task3*/ logMsg("Please reput the other command!\n"); msgQReceive(myMsgQId1,(char*)&rxMsg,MAX_MSG_LEN,WAIT_FOREVER); /*recive MsgQ from task3*/ } if(rxMsg->mRecvId==MID_MESSAGE(2)) /*receive MsgQ from task2*/ { message=test_end(rxMsg->Data,"sysend"); if(message) { /*if the message from task2 is "sysend" and did not receive the warn from task3, close the system*/ if(singal) { bye(); } } else {/*if the message from task2 is "sysend" and receive the warn from task3, reput the command*/ if(singal) logMsg("task2 receiveing a %s\n",rxMsg->Data); logMsg("please reput the correct command!\n"); } } } return; } /********************************************************************************************/ int change_buf(char *command) { int ret; if(!strcmp(command,"add")) ret=1; else if(!strcmp(command,"sub")) ret=2; else if(!strcmp(command,"multiply")) ret=3; else if(!strcmp(command,"divide")) ret=4; else if(!strcmp(command,"testcommand")) ret=5; else ret=0; return ret; } /****************************************[task2]*********************************************/ /*console 命令接收Task。接收并分析console发来的命令及参数。自设置5种以上命令,并根据命*/ /*令的内容向Task3发送激励消息。同时实现系统退出命令,使系统采用适当方式安全退出。收到非法命令*/ /*向Task1告警*/ int task2(void) { char buf[100]; int command; char *str=mymalloc(35); MESSAGE *txMsg=mymalloc(26); memset(str,0,35); memset(txMsg,0,26); txMsg->mSendId=MID_MESSAGE(2); txMsg->mRecvId=MID_MESSAGE(2); FOREVER { semTake(syncSemId,WAIT_FOREVER); semTake(waitSemId,WAIT_FOREVER); gets(buf); command=change_buf(buf);/*change the commands into numbers*/ switch(command) { case 0:/*receive uncorrect command*/ txMsg->mData=0; strcpy(txMsg->Data,"wrong command");/*send warn to task1*/ msgQSend(myMsgQId1,(char*)&txMsg,sizeof(txMsg),WAIT_FOREVER,MSG_PRI_NORMAL); break; case 1:/*receive add command*/ strcpy(str,"This an add caculate!\0"); txMsg->mData=1; break; case 2:/*receive sub command*/ strcpy(str,"This a sub caculate!\0"); txMsg->mData=2; break; case 3:/*receive multiply command*/ strcpy(str,"This a multiply caculate!\0"); txMsg->mData=3; break; case 4:/*receive divide command*/ strcpy(str,"This a divide caculate!\0"); txMsg->mData=4; break; case 5:/*receive testcommand,send a long string to task3*/ strcpy(str,"This a testcommand to warn task1!\0"); txMsg->mData=5; break; default: break; } if(txMsg->mData!=0) {/*send along string to task3,and send a message to taks3*/ msgQSend(myMsgQId3,(char*)&str,sizeof(str),WAIT_FOREVER,MSG_PRI_NORMAL); msgQSend(myMsgQId3,(char*)&txMsg,sizeof(txMsg),WAIT_FOREVER,MSG_PRI_NORMAL); } semGive(waitSemId); semGive(syncSemId); taskDelay(DELAY_TICKS); if(txMsg->mData!=0) {/*send sysend to task1 to let task1 close system*/ strcpy(txMsg->Data,"sysend"); msgQSend(myMsgQId1,(char*)&txMsg,sizeof(txMsg),WAIT_FOREVER,MSG_PRI_NORMAL); } } return; } /****************************************[task3]********************************************/ /*console输出Task。接收需打印输出的字串消息命令),输出到console。收到长度为0或超常字串向*/ /*Task1告警*/ int task3(void) { int firstData=100; int secondData=10; MESSAGE *rxMsg=mymalloc(26); MESSAGE *txMsg=mymalloc(26); char *rstr=mymalloc(35); memset(txMsg,0,26); memset(txMsg,0,26); memset(rstr,0,35); txMsg->mSendId=MID_MESSAGE(3); txMsg->mRecvId=MID_MESSAGE(3); while(1) { semTake(syncSemId,WAIT_FOREVER); msgQReceive(myMsgQId3,(char*)&rstr,sizeof(rstr),WAIT_FOREVER); if(strlen(rstr)=26) {/*make sure whether the string is too long or short*/ strcpy(txMsg->Data,"wrong length"); msgQSend(myMsgQId1,(char*)&txMsg,sizeof(txMsg),WAIT_FOREVER,MSG_PRI_NORMAL); /*msgQReceive(myMsgQId3,(char*)&rxMsg,sizeof(rxMsg),WAIT_FOREVER);*/ } semTake(waitSemId,WAIT_FOREVER); msgQReceive(myMsgQId3,(char*)&rxMsg,sizeof(rxMsg),WAIT_FOREVER); if(rxMsg->mData!=5) {/*when it is not testcommand,printf these*/ printf("%s\n",rstr); printf("there are two datas!\n"); printf("firstData:100\n"); printf("secondData:10\n"); } switch(rxMsg->mData) { case 1:/*printf add caculate*/ printf("The result is:%d\n",firstData+secondData); break; case 2:/*printf sub caculate*/ printf("The result is:%d\n",firstData-secondData); break; case 3:/*printf multiply caculate*/ printf("The result is:%d\n",firstData*secondData); break; case 4:/*printf divide caculate*/ printf("The result is:%d\n",firstData/secondData); break; case 5: break; default: break; } semGive(waitSemId); semGive(syncSemId); taskDelay(DELAY_TICKS); } return; } template T* mymalloc(unsigned nBytes) { T* point; int i=0; /*用户分区一是否能分配的标志位*/ int j=0; /*用户分区二是否能分配的标志位*/ if(nBytes=size_1 && nBytes=size_2) && point3_index<MAX_point) /*若用户分区二不能分配,由系统内存池来分配,且只能从系统内存池中分配MAX_point次*/ { point=malloc(nBytes); point3[point3_index]=point; printf("the number of the point3_index is:%d\n",point3_index); point3_index++; } return point; } void myfree(void) { int i=0; for (i=0;i<point1_index;i++) { memPartFree(partid1,point1[i]); } for (i=0;i<point2_index;i++) { memPartFree(partid2,point2[i]); } for (i=0;i<point3_index;i++) { free(point3[i]); } free(usermem1); free(usermem2); printf("The memory have freed!\n"); } void bye(void) { myfree(); logMsg("Bye-bye\n"); taskDelete(tidtask2); taskDelete(tidtask3); msgQDelete(myMsgQId1); msgQDelete(myMsgQId2); msgQDelete(myMsgQId3); semDelete(syncSemId); taskDelete(tidtask1); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值