1. 程式人生 > >Linux 程序間通訊——訊息佇列實現雙向通訊

Linux 程序間通訊——訊息佇列實現雙向通訊

函式: key_t ftok(const char *filename, int proj_id);
通過檔名和專案號獲得System V IPC鍵值(用於建立訊息佇列、共享記憶體所用)
proj_id:專案號,不為0即可
返回:成功則返回鍵值,失敗則返回-1


函式: int msgget(key_t key, int msgflg);
key:鍵值,當為IPC_PRIVATE時新建一塊共享記憶體;
shmflg:標誌。
IPC_CREAT:記憶體不存在則新建,否則開啟;
IPC_EXCL:只有在記憶體不存在時才建立,否則出錯。
返回:成功則返回識別符號,出錯返回-1


函式: int msgsnd(int msgid, const void *msgp, size_t sz, int flg);
向訊息佇列傳送訊息
msgid:通過msgget獲取
msgp:指向訊息內容的指標
sz:訊息內容的大小
flg:處理方式;如為IPC_NOWAIT時表示空間不足時不會阻塞
返回:成功則返回0,失敗返回-1


函式: int msgrcv(int msgid, void *msgp, size_t sz, long type, int flg);
從訊息佇列讀取訊息
msgid:通過msgget獲取
msgp:指向訊息內容的指標
sz:訊息內容的大小
type:指定接收的訊息型別;若為0則佇列第一條訊息將被讀取,而不管型別;若大於0則佇列中同類型的訊息將被讀取,如在flg中設了MSG_RXCEPT位將讀取指定型別的其他訊息;若小於0讀取絕對值小於type的訊息。
flg:處理方式;
返回:成功返回收到訊息長度,錯誤返回-1


函式: int msgctl(int msgid, int cmd, struct msgid_ds *buf);
msgid:通過msgget獲取
cmd:控制命令,如下:
IPC_STAT:獲取訊息佇列狀態
IPC_SET:改變訊息佇列狀態
IPC_RMID:刪除訊息佇列
buf:結構體指標,用於存放訊息佇列狀態

返回:成功返回與cmd相關的正數,錯誤返回-1

Client.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define N 1024
#define Pathname "/tmp/xkeyideal"
#define MODE IPC_CREAT|IPC_EXCL|0666
#define ID 27
#define SENDMSG 1
#define RECVMSG 2

struct msgbuf{
	int type;
	int a;
	int b;
	char text[N];
}msg_rbuf,msg_sbuf;

int main(){
	key_t key;
	key = ftok(Pathname,ID);
	int msgid;
	msgid = msgget(key,MODE);
	if(msgid == -1){
		printf("error");
		exit(1);
	}
	while(1){
		pid_t pid,pid_wait;
		pid = fork();
		if(pid > 0){
			pid_wait = waitpid(pid,NULL,0);//父程序等待子程序先執行
			printf("Parent process recv msg,pid = %d\n",getpid());
			msgrcv(msgid,&msg_rbuf,sizeof(msg_rbuf),SENDMSG,0);
			int a = msg_rbuf.a;
			int b = msg_rbuf.b;
			printf("color: Receive: %s, sum %d + %d = %d\n",msg_rbuf.text,a,b,a+b);
		}else if(pid == 0){
			char str[N];
			printf("Child process send msg, pid = %d\n",getpid());
			printf("Please input msg info str ,a ,b\n");
			scanf("%s %d %d",str,&msg_sbuf.a,&msg_sbuf.b);
			strcpy(msg_sbuf.text,str);
			msg_sbuf.type = RECVMSG;
			msgsnd(msgid,&msg_sbuf,sizeof(msg_sbuf),IPC_NOWAIT);
			exit(0);
		}
	}
	msgctl(msgid,IPC_RMID,NULL);
	exit(0);
}

Server.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#define N 1024
#define Pathname "/tmp/xkeyideal"
#define MODE IPC_CREAT|IPC_EXCL|0666
#define ID 27
#define SENDMSG 1
#define RECVMSG 2

struct msgbuf{
	int type;
	int a;
	int b;
	char text[N];
}msg_rbuf;
struct msgbuf2{
	int type;
	int a;
	int b;
	char text[N];
}msg_sbuf;

int main(){
	key_t key;
	key = ftok(Pathname,ID);
	int msgid;
	msgid = msgget(key,0);//這裡和上面的有不同
	if(msgid == -1){
		perror("Msgqueue has exist");
		exit(1);
	}
	while(1){
		pid_t pid;
		pid = fork();
		if(pid > 0){//parent
			wait(NULL);
			msg_sbuf.type = SENDMSG;
			char str[N];
			printf("Please input info: name , a, b\n");
			scanf("%s %d %d",str,&msg_sbuf.a,&msg_sbuf.b);
			strcpy(msg_sbuf.text,str);
			printf("Parent process send msg, pid = %d\n",getpid());
			msgsnd(msgid, &msg_sbuf,sizeof(msg_sbuf),IPC_NOWAIT);
		}else if(pid == 0){
			msgrcv(msgid,&msg_rbuf,sizeof(msg_rbuf),RECVMSG,0);
			printf("Child process recv msg, pid = %d\n",getpid());
			printf("xkey: Receive: %s, sum %d + %d = %d \n",msg_rbuf.text,msg_rbuf.a,msg_rbuf.b,msg_rbuf.a+msg_rbuf.b);
			exit(1);
		}
	}
	msgctl(msgid,IPC_RMID,NULL);
	exit(0);
}

先啟動Client再啟動Server

另:在終端輸入ipcs -q能看到建立的訊息佇列,ipcrm -q <msgqid>能夠手動刪除該訊息佇列