我會用幾篇博客總結一下在Linux中進程之間通信的幾種方法,我會把這個開頭的摘要部分在這個系列的每篇博客中都打出來
進程之間通信的方式
這次主要寫的是消息隊列,之前講過的管道和消息隊列在本質上就有很大的區別,管道是一個文件,而消息隊列是一個數據結構(類似於鏈表)。這說明了,管道文件是存放在磁盤上的,關機也會存在(尤其是命名管道更為顯而易見,你不刪除他他就擱那呆著),而消息隊列是存在於內核中的內存,顯而易見,關機就沒了。
更關鍵的是,內存他快呀,比磁盤I/O快多了,為啥要用那麼慢的管道。而且消息隊列是可以直接完成沒有親緣關系的進程之間的通信的。但是結構比起管道要復雜,用到了很多結構體。內容有些多。先寫一下和管道的主要區別,可以更直觀的進行對比
那麼從頭開始吧:
在C庫函數中有一個系統調用可以創建一個消息隊列,那就是msgget,跟這個函數有關的其他函數也會一並給出來
相關函數就這麼多,到這裡就可以開心的創建一個新的消息隊列了,那麼怎麼看我們創建出來的消息隊列呢?怎麼銷毀他呢?
先用命令看一下,使用ipcs -q就可查看消息隊列的狀態,這裡我創建了一個消息隊列,下面來銷毀它
使用ipcrm -q msqid就可以銷毀一個消息隊列,我已經把剛才創建的消息隊列銷毀了
那麼如何通過C函數銷毀一個消息隊列?使用msgctl函數
這裡提一下,消息隊列的一個缺點,這裡說到IPC_SET對消息隊列的初始化,就是說消息隊列的創建和初始化是分開的,這樣設計不是很好,因為有線程安全的問題,當一個線程創建了消息隊列還沒初始化,另一個線程直接開始執行訪問的操作就很尴尬了
1 struct msginfo { 2 int msgpool; /* Size in kibibytes of buffer pool 3 used to hold message data; 4 unused within kernel */ 5 int msgmap; /* Maximum number of entries in message 6 map; unused within kernel */ 7 int msgmax; /* Maximum number of bytes that can be 8 written in a single message */ 9 int msgmnb; /* Maximum number of bytes that can be 10 written to queue; used to initialize 11 msg_qbytes during queue creation 12 (msgget(2)) */ 13 int msgmni; /* Maximum number of message queues */ 14 int msgssz; /* Message segment size; 15 unused within kernel */ 16 int msgtql; /* Maximum number of messages on all queues 17 in system; unused within kernel */ 18 unsigned short int msgseg; 19 /* Maximum number of segments; 20 unused within kernel */ 21 };
提到使用消息隊列無非就是消息的寫入和消息的讀出,這涉及兩個函數和一個結構體
先說發送函數
在列接受函數之前必須把結構體放出來,不然下面就懵逼了
1 struct msgbuf { 2 long mtype; /* message type, must be > 0 */ 3 char mtext[1]; /* message data */ 4 };
從mtype講起,因為隊列是好多進程(或者說是線程)都拿來用的,比如4個進程共用一個消息隊列,兩兩之間進行通信,就有必要標識哪兩個進程是一組的,哪塊數據是屬於你們組的,不能亂拿是不是,這個mtype就是用來標識的,但是一定要大於0,我一開始設置為0一直報參數錯誤,查了文檔才發現自己蠢了。。。
mtext存放的就是你要傳輸的數據了,怎麼大小只有1?當然不能只有1,我自己寫的msgbuf就有1024長度。。。所以還是自己寫爽啊
可以說接受函數了
事已至此,基本操作就說完了,廢話少說,show me the code
我的程序分為comm.h(公共頭文件) comm.c(封裝基本函數) server.c(建議服務器端) client.c(簡易客戶端)一共4個文件
完成了服務器端和客戶端的簡單通信(回合制聊天(誤))
comm.h
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <sys/msg.h> 4 #include <sys/types.h> 5 #include <sys/ipc.h> 6 #include <string.h> 7 #include <stdlib.h> 8 #include <errno.h> 9 #include <memory.h> 10 11 12 #define _PATH_NAME_ "/tmp" 13 #define _PROJ_ID_ 0x666 14 #define _SIZE_ 1024 15 16 static int comm_create_msg_set(int flags); 17 int create_msg_set(); 18 int get_msg_set(); 19 void destory_msg_set(int msg_id); 20 void send_msg(int msg_id,long msgtype,char * buf); 21 void receive_msg(int msg_id,long msgtype,char *buf); 22 23 24 25 struct msgbuf 26 { 27 long mtype; 28 char mtext[_SIZE_]; 29 };
comm.c
1 #include "comm.h" 2 static int comm_create_msg_set(int flags) 3 { 4 key_t _key=ftok(_PATH_NAME_,_PROJ_ID_); 5 if(_key<0) 6 { 7 printf("%d:%s",errno,strerror(errno)); 8 } 9 int msg_id=msgget(_key,flags); 10 if(msg_id<0) 11 { 12 printf("%d:%s",errno,strerror(errno)); 13 } 14 return msg_id; 15 } 16 17 18 int get_msg_set() 19 { 20 key_t _key=ftok(_PATH_NAME_,_PROJ_ID_); 21 int flags=IPC_CREAT; 22 return comm_create_msg_set(flags); 23 } 24 25 26 int create_msg_set() 27 { 28 key_t _key=ftok(_PATH_NAME_,_PROJ_ID_); 29 int flags=IPC_CREAT | IPC_EXCL; 30 return comm_create_msg_set(flags); 31 } 32 33 34 void send_msg(int msg_id,long msgtype,char *buf) 35 { 36 memset(buf,'\0',strlen(buf)+1); 37 ssize_t _size=read(0,buf,_SIZE_); 38 if(_size>0) 39 { 40 buf[_size-1]='\0'; 41 } 42 43 struct msgbuf _mbuf; 44 memset(&_mbuf,'\0',sizeof(struct msgbuf)); 45 _mbuf.mtype=msgtype; 46 strcpy(_mbuf.mtext,buf); 47 if(msgsnd(msg_id,&_mbuf,_size,0)<0) 48 { 49 printf("send error,%d:%s",errno,strerror(errno)); 50 } 51 } 52 53 void receive_msg(int msg_id , long msgtype ,char *buf) 54 { 55 struct msgbuf _mbuf; 56 memset(&_mbuf,'\0',sizeof(struct msgbuf)); 57 _mbuf.mtype=0; 58 if(msgrcv(msg_id,&_mbuf,_SIZE_,msgtype,0)<0) 59 { 60 printf("recv error %d:%s",errno,strerror(errno)); 61 } 62 strcpy(buf,_mbuf.mtext); 63 } 64 65 void destory_msg_set(int msg_id) 66 { 67 if(msgctl(msg_id,IPC_RMID,0)<0) 68 { 69 printf("%d:%s",errno,strerror(errno)); 70 } 71 }
server.c
1 #include "comm.h" 2 long c_type=1; 3 long s_type=22; 4 int main() 5 { 6 int msg_id=create_msg_set(); 7 char buf[_SIZE_]; 8 9 while(1) 10 { 11 memset(buf,'\0',sizeof(buf)); 12 receive_msg(msg_id,c_type,buf); 13 if(strcasecmp(buf,"quit")==0) 14 { 15 break; 16 } 17 printf("client # %s\n",buf); 18 printf("clent say done ! Please Input:"); 19 fflush(stdout); 20 memset(buf,'\0',sizeof(buf)); 21 send_msg(msg_id,c_type,buf); 22 } 23 destory_msg_set(msg_id); 24 return 0; 25 }
client.c
1 #include "comm.h" 2 3 4 long c_type=1; 5 long s_type=2; 6 7 int main() 8 { 9 int msg_id = get_msg_set(); 10 11 char buf[_SIZE_]; 12 13 while(1) 14 { 15 memset(buf,'\0',sizeof(buf)); 16 send_msg(msg_id,c_type,buf); 17 if(strcasecmp(buf,"quit")==0) 18 { 19 break; 20 } 21 memset(buf,'\0',sizeof(buf)); 22 receive_msg(msg_id,c_type,buf); 23 printf("server # %s\n",buf); 24 printf("server say done ! Please Input:"); 25 fflush(stdout); 26 } 27 28 return 0; 29 }
http://xxxxxx/Linuxjc/1139910.html TechArticle