Linux學習之程序通訊(五)
言之者無罪,聞之者足以戒。 ——《詩序》
訊息佇列:
鏈式佇列:
msqid ds 維護訊息佇列的結構體,佇列的第一個訊息指標msg_first,最後一個訊息指標msg_last
訊息中有一個成員指標next
每一個訊息中包含有哪些內容:
Data 資料
Length 資料的長度
Type 資料的型別
訊息的接收端可以根據訊息的型別來接收。
訊息佇列與檔案IO的對比:
檔案I/O |
訊息佇列 |
open(開啟檔案) |
msg_get(建立訊息佇列) |
read(讀資料) |
msgrcv(從訊息佇列中讀資料) |
write(寫資料) |
msgsnd(向訊息佇列中寫資料) |
close(關閉檔案) |
msgctl(刪除訊息對列) |
1、msgget:建立訊息佇列
所需標頭檔案 |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> |
函式原型 |
int msgget(key_t key, int flag); |
函式引數 |
key:和訊息佇列關聯的key值;可以用巨集定義IPC_PRIVATE,也可以用ftok()函式 |
flag:訊息佇列的訪問許可權 |
|
函式返回值 |
成功:訊息佇列ID |
出錯:-1 |
2、msgctl:刪除訊息佇列
所需標頭檔案 |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> |
|
函式原型 |
int msgctl ( int msgqid, int cmd, struct msqid_ds *buf ); |
|
函式引數 |
msqid:訊息佇列的佇列ID |
|
cmd: |
IPC_STAT:讀取訊息佇列的屬性,並將其儲存在buf指向的緩衝區中。 |
|
IPC_SET:設定訊息佇列的屬性。這個值取自buf引數。 |
||
IPC_RMID:從系統中刪除訊息佇列。 |
||
buf:訊息佇列緩衝區 |
||
函式返回值 |
成功:0 |
|
出錯:-1 |
下面我們來看一下關於這兩個函式的程式:
#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
int main()
{
int msgid;
msgid=msgget(IPC_PRIVATE,0777);
if(msgid < 0)
{
printf("creat message queue failure\n");
return -1;
}
printf("creat message queue sucess msgid=%d\n",msgid);
system("ipcs -q");
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
3、msgsnd:向訊息佇列中寫入資料
所需標頭檔案 |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> |
|
函式原型 |
int msgsnd(int msqid, const void *msgp, size_t size, int flag); |
|
函式引數 |
msqid:訊息佇列的ID |
|
msgp:指向訊息的指標。常用訊息結構msgbuf如下: struct msgbuf { long mtype; //訊息型別 char mtext[N] //訊息正文 }; |
||
size:傳送的訊息正文的位元組數 |
||
flag: |
IPC_NOWAIT 訊息沒有傳送完成函式也會立即返回。 |
|
0:直到傳送完成函式才返回 |
||
函式返回值 |
成功:0 |
|
出錯:-1 |
4、msgrcv:從訊息佇列中讀取資料
所需標頭檔案 |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> |
|
函式原型 |
int msgrcv(int msgid, void* msgp, size_t size, long msgtype, int flag); |
|
函式引數 |
msqid:訊息佇列的ID |
|
msgp:接收訊息的緩衝區 |
||
size:要接收的訊息的位元組數 |
||
msgtype: |
0:接收訊息佇列中第一個訊息。 |
|
大於0:接收訊息佇列中第一個型別為msgtyp的訊息. |
||
小於0:接收訊息佇列中型別值不大於msgtyp的絕對值且型別值又最小的訊息。 |
||
flag: |
0:若無訊息函式會一直阻塞 |
|
IPC_NOWAIT:若沒有訊息,程序會立即返回ENOMSG。 |
||
函式返回值 |
成功:接收到的訊息的長度 |
|
出錯:-1 |
訊息佇列中資料讀後,資料也不存在了
下面看一下程式:
#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
struct msgbuf
{
long type;
char voltage[124];
char ID[4];
};
int main()
{
int msgid;
int readret;
struct msgbuf sendbuf,recvbuf;
msgid=msgget(IPC_PRIVATE,0777);
if(msgid < 0)
{
printf("creat message queue failure\n");
return -1;
}
printf("creat message queue sucess msgid=%d\n",msgid);
system("ipcs -q");
sendbuf.type=100;
printf("please input message:\n");
fgets(sendbuf.voltage,124,stdin);
msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
memset(recvbuf.voltage,0,124);
readret=msgrcv(msgid,(void *)&recvbuf,124,100,0);
printf("recv:%s",recvbuf.voltage);
printf("readret=%d\n",readret);
msgrcv(msgid,(void *)&recvbuf,124,100,0);
printf("second read after\n");
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
(1)下面我們用一個訊息佇列實現無親緣關係的程序的單向通訊:
write函式:
#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
struct msgbuf
{
long type;
char voltage[124];
char ID[4];
};
int main()
{
int msgid;
int readret;
struct msgbuf sendbuf,recvbuf;
int key;
key=ftok("./a.c",'a');
if(key < 0)
{
printf("creat key failure\n");
return -2;
}
msgid=msgget(key,IPC_CREAT | 0777);
if(msgid < 0)
{
printf("creat message queue failure\n");
return -1;
}
printf("creat message queue sucess msgid=%d\n",msgid);
system("ipcs -q");
sendbuf.type=100;
while(1)
{
memset(sendbuf.voltage,0,124);//clear send buffer
printf("please input message:\n");
fgets(sendbuf.voltage,124,stdin);//input from key panel
msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
}
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
read函式:
#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
struct msgbuf
{
long type;
char voltage[124];
char ID[4];
};
int main()
{
int msgid;
int readret;
struct msgbuf sendbuf,recvbuf;
int key;
key=ftok("./a.c",'a');
if(key < 0)
{
printf("creat key failure\n");
return -2;
}
msgid=msgget(key,IPC_CREAT | 0777);
if(msgid < 0)
{
printf("creat message queue failure\n");
return -1;
}
printf("creat message queue sucess msgid=%d\n",msgid);
system("ipcs -q");
sendbuf.type=100;
while(1)
{
memset(recvbuf.voltage,0,124);//clear receive buffer
msgrcv(msgid,(void *)&recvbuf,124,100,0);
printf("receive data from message queue:%s",recvbuf.voltage);
}
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
(2)用訊息佇列實現父子程序的雙通訊
server函式:
#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
struct msgbuf
{
long type;
char voltage[124];
char ID[4];
};
int main()
{
int msgid;
int readret;
int pid;
struct msgbuf sendbuf,recvbuf;
int key;
key=ftok("./b.c",'a');
if(key < 0)
{
printf("creat key failure\n");
return -2;
}
msgid=msgget(key,IPC_CREAT | 0777);
if(msgid < 0)
{
printf("creat message queue failure\n");
return -1;
}
printf("creat message queue sucess msgid=%d\n",msgid);
system("ipcs -q");
pid=fork();
if(pid > 0)//parent process write 100
{
sendbuf.type=100;
//write message queue
while(1)
{
memset(sendbuf.voltage,0,124);
printf("please input message:\n");
fgets(sendbuf.voltage,124,stdin);
msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
}
}
if(pid == 0)//child process read 200
{
while(1)
{
memset(recvbuf.voltage,0,124);
msgrcv(msgid,(void *)&recvbuf,124,200,0);
printf("receive message from message queue:%s",recvbuf.voltage);
}
}
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
client函式:
#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
struct msgbuf
{
long type;
char voltage[124];
char ID[4];
};
int main()
{
int msgid;
int readret;
int pid;
struct msgbuf sendbuf,recvbuf;
int key;
key=ftok("./b.c",'a');
if(key < 0)
{
printf("creat key failure\n");
return -2;
}
msgid=msgget(key,IPC_CREAT | 0777);
if(msgid < 0)
{
printf("creat message queue failure\n");
return -1;
}
printf("creat message queue sucess msgid=%d\n",msgid);
system("ipcs -q");
pid=fork();
if(pid == 0)//child process write 200
{
sendbuf.type=200;
//write message queue
while(1)
{
memset(sendbuf.voltage,0,124);
printf("please input message:\n");
fgets(sendbuf.voltage,124,stdin);
msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
}
}
if(pid > 0)//parent process read 100
{
while(1)
{
memset(recvbuf.voltage,0,124);
msgrcv(msgid,(void *)&recvbuf,124,100,0);
printf("receive message from message queue:%s",recvbuf.voltage);
}
}
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
上面的兩個程式實現了父子程序的雙通訊;在server程式中父程序以type為100來發送資料,子程序以type為200來接收資料;在client程式中父程序以type為100來接收資料,子程序以type為200來發送資料。這樣就實現了在一個訊息佇列中的雙通訊。