『壹』 請教一個關於linux消息隊列的問題
一般使用步驟:
1. 用ftok產生一個key。
2. 調用msgget(使用key作為參數)產生一個隊列
3. 進程可以用msgsnd發送消息到這個隊列,相應的別的進程用msgrcv讀取。
這里需要注意msgsnd可能會失敗的兩個情況:
a) 可能被中斷打斷(包括msgsnd和msgrcv). 尤其是大流量應用中更容易出現. 比較安全的用法是判斷操作是否被中斷打斷,如果被打斷, 則需要繼續嘗試。
b) 消息隊列滿。產生這個錯誤,則需要考慮提高系統消息隊列規格,或者查看消息接收處是否有問題
4. msgctl函數可以用來刪除消息隊列
消息隊列產生之後,除非明確的刪除(可以用),產生的隊列會一直保留在系統中。linux下消息隊列的個數是有限的,注意不要泄露。如果 使用已經達到上限,msgget調用會失敗,產生的錯誤碼對應的提示信息為no space left on device.
注意點:
1.消息的類型 mtype 不需為非0值。如果使用0,則msgsnd會失敗,並得到」Invalid argument「錯誤。
2.msgflg為0表示阻塞等待,如果msgflg為IPC_NOWAIT表示非阻塞。
3.最好使用root許可權執行消息隊列,否則msgrcv 提示 "Permission denied"。
『貳』 如何在linux下看消息隊列是否存在
#include
#include
#include
#include types.h>
#include msg.h>
#include
#include ipc.h>
void msg_show_attr(int msg_id, struct msqid_ds msg_info)
{
int ret = -1;
sleep(1);
ret = msgctl(msg_id, IPC_STAT, &msg_info);
if( -1 == ret)
{
printf(獲消息信息失敗\n);
return ;
}
printf(\n);
printf(現隊列位元組數:%d\n,msg_info.msg_cbytes);
printf(隊列消息數:%d\n,msg_info.msg_qnum);
printf(隊列位元組數:%d\n,msg_info.msg_qbytes);
printf(發送消息進程pid:%d\n,msg_info.msg_lspid);
printf(接收消息進程pid:%d\n,msg_info.msg_lrpid);
printf(發送消息間:%s,ctime(&(msg_info.msg_stime)));
printf(接收消息間:%s,ctime(&(msg_info.msg_rtime)));
printf(變化間:%s,ctime(&(msg_info.msg_ctime)));
printf(消息UID:%d\n,msg_info.msg_perm.uid);
printf(消息GID:%d\n,msg_info.msg_perm.gid);
}
int main(void)
{
int ret = -1;
int msg_flags, msg_id;
key_t key;
struct msgmbuf{
int mtype;
char mtext[10];
};
struct msqid_ds msg_info;
struct msgmbuf msg_mbuf;
int msg_sflags,msg_rflags;
char *msgpath = /ipc/msg/;
key = ftok(msgpath,』a');
if(key != -1)
{
printf(功建立KEY\n);
}
else
{
printf(建立KEY失敗\n);
}
msg_flags = IPC_CREAT;
msg_id = msgget(key, msg_flags|0666);
if( -1 == msg_id)
{
printf(消息建立失敗\n);
return 0;
}
msg_show_attr(msg_id, msg_info);
msg_sflags = IPC_NOWAIT;
msg_mbuf.mtype = 10;
memcpy(msg_mbuf.mtext,測試消息,sizeof(測試消息));
ret = msgsnd(msg_id, &msg_mbuf, sizeof(測試消息), msg_sflags);
if( -1 == ret)
{
printf(發送消息失敗\n);
}
msg_show_attr(msg_id, msg_info);
msg_rflags = IPC_NOWAIT|MSG_NOERROR;
ret = msgrcv(msg_id, &msg_mbuf, 10,10,msg_rfla
共享內存示例代碼:
#include
#include sem.h>
#include ipc.h>
#include
typedef int sem_t;
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
sem_t CreateSem(key_t key, int value)
{
union semun sem;
sem_t semid;
sem.val = value;
semid = semget(key,value,IPC_CREAT|0666);
if (-1 == semid)
{
printf(create semaphore error\n);
return -1;
}
semctl(semid,0,SETVAL,sem);
return semid;
}
/*
struct sembuf{
ushort sem_num;
short sem_op;
short sem_flg;
};
*/
void SetvalueSem(sem_t semid, int value)
{
union semun sem;
sem.val = value;
semctl(semid,0,SETVAL,sem);
return ;
}
int GetvalueSem(sem_t semid)
{
union semun sem;
return semctl(semid,0,GETVAL,sem);
return sem.val;
}
void DestroySem(sem_t semid)
{
union semun sem;
sem.val = 0;
semctl(semid,0,IPC_RMID,sem);
}
int Sem_P(sem_t semid)
{
struct sembuf sops={0,+1,IPC_NOWAIT};
return (semop(semid,&sops,1));
}
int Sem_V(sem_t semid)
{
struct sembuf sops={0,-1,IPC_NOWAIT};
return (semop(semid,&sops,1));
}
static char msg[]=共享內存\n;
int main(void)
{
key_t key;
int semid,shmid;
char i,*shms,*shmc;
struct semid_ds buf;
int value = 0;
char buffer[80];
pid_t p;
key = ftok(/ipc/sem/,』a');
shmid = shmget(key,1024,IPC_CREAT|0604);
semid = CreateSem(key,1);
p = fork();
if(p > 0)
{
/* 父進程 */
/* 建立共享內存 */
shms = (char *)shmat(shmid,0,0);
memcpy(shms, msg, strlen(msg)+1);
sleep(10);
Sem_P(semid);
shmdt(shms);
DestroySem(semid);
}
else if(p == 0)
{
shmc = (char *)shmat(shmid,0,0);
Sem_V(semid);
printf(共享內存值:%s\n,shmc);
shmdt(sg_
『叄』 Linux多線程同步之消息隊列有何特點
消息隊列是消息的鏈表,存放在內核中並有消息隊列標示符標示。
msgget用於創建一個新隊列或打開一個現存的隊列。msgsnd將新消息加入到消息隊列中;每個
消息包括一個long型的type;和消息緩存;msgrcv用於從隊列中取出消息;取消息很智能,不一定先進先出
①msgget,創建一個新隊列或打開一個現有隊列
#include
int msgget ( key_t key, int flag );
//成功返回消息隊列ID;錯誤返回-1
②msgsnd: 發送消息
#include
int msgsnd( int msgid, const void* ptr, size_t nbytes, int flag )
//成功返回0,錯誤返回-1
a:
flag可以指定為IPC_NOWAIT;
若消息隊列已滿,則msgsnd立即出錯返回EABAIN;
若沒指定IPC_NOWAIT; msgsnd會阻塞,直到消息隊列有空間為止
③msgrcv: 讀取消息:
ssize_t msgrcv( int msgid, void* ptr, size_t nbytes, long type, int flag );
a. type == 0; 返回消息隊列中第一個消息,先進先出
b. type > 0
返回消息隊列中類型為tpye的第一個消息
c. type < 0
返回消息隊列中類型 <=
|type| 的數據;若這種消息有若干個,則取類型值最小的消息
消息隊列創建步驟:
#define
MSG_FILE "."
struct msgtype {
long mtype;
char buffer[BUFFER+1];
};
if((key=ftok(MSG_FILE,'a'))==-1)
{
fprintf(stderr,"Creat Key Error:%s\n", strerror(errno));
exit
(1);
}
if((msgid=msgget(key, IPC_CREAT | 0666/*PERM*/))==-1)
{
fprintf(stderr,"Creat Message
Error:%s\n", strerror(errno));
exit
(1);
}
『肆』 Linux系統編程—消息隊列
消息隊列本質上是位於內核空間的鏈表,鏈表的每個節點都是一條消息。每一條消息都有自己的消息類型,消息類型用整數來表示,而且必須大於 0。每種類型的消息都被對應的鏈表所維護:
其中數字 1 表示類型為 1 的消息,數字2、3、4 類似。彩色塊表示消息數據,它們被掛在對應類型的鏈表上。
值得注意的是,剛剛說過沒有消息類型為 0 的消息,實際上,消息類型為 0 的鏈表記錄了所有消息加入隊列的順序,其中紅色箭頭表示消息加入的順序。
無論你是發送還是接收消息,消息的格式都必須按照規范來。簡單的說,它一般長成下面這個樣子:
所以,只要你保證首4位元組(32 位 linux 下的 long)是一個整數就行了。
舉個例子:
從上面可以看出,正文部分是什麼數據類型都沒關系,因為消息隊列傳遞的是 2 進制數據,不一定非得是文本。
msgsnd 函數用於將數據發送到消息隊列。如果該函數被信號打斷,會設置 errno 為 EINTR。
參數 msqid:ipc 內核對象 id
參數 msgp:消息數據地址
參數 msgsz:消息正文部分的大小(不包含消息類型)
參數 msgflg:可選項
該值為 0:如果消息隊列空間不夠,msgsnd 會阻塞。
IPC_NOWAIT:直接返回,如果空間不夠,會設置 errno 為 EAGIN.
返回值:0 表示成功,-1 失敗並設置 errno。
msgrcv 函數從消息隊列取出消息後,並將其從消息隊列里刪除。
參數 msqid:ipc 內核對象 id
參數 msgp:用來接收消息數據地址
參數 msgsz:消息正文部分的大小(不包含消息類型)
參數 msgtyp:指定獲取哪種類型的消息
msgtyp = 0:獲取消息隊列中的第一條消息
msgtyp > 0:獲取類型為 msgtyp 的第一條消息,除非指定了 msgflg 為MSG_EXCEPT,這表示獲取除了 msgtyp 類型以外的第一條消息。
msgtyp < 0:獲取類型 ≤|msgtyp|≤|msgtyp| 的第一條消息。
參數 msgflg:可選項。
如果為 0 表示沒有消息就阻塞。
IPC_NOWAIT:如果指定類型的消息不存在就立即返回,同時設置 errno 為 ENOMSG
MSG_EXCEPT:僅用於 msgtyp > 0 的情況。表示獲取類型不為 msgtyp 的消息
MSG_NOERROR:如果消息數據正文內容大於 msgsz,就將消息數據截斷為 msgsz
程序 msg_send 和 msg_recv 分別用於向消息隊列發送數據和接收數據。
msg_send 程序定義了一個結構體 Msg,消息正文部分是結構體 Person。該程序向消息隊列發送了 10 條消息。
msg_send.c
程序 msg_send 第一次運行完後,內核中的消息隊列大概像下面這樣:
msg_recv 程序接收一個參數,表示接收哪種類型的消息。比如./msg_recv 4 表示接收類型為 4 的消息,並列印在屏幕。
先運行 msg_send,再運行 msg_recv。
接收所有消息
接收類型為 4 的消息
獲取和設置消息隊列的屬性
msqid:消息隊列標識符
cmd:控制指令
IPC_STAT:獲得msgid的消息隊列頭數據到buf中
IPC_SET:設置消息隊列的屬性,要設置的屬性需先存儲在buf中,可設置的屬性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes
buf:消息隊列管理結構體。
返回值:
成功:0
出錯:-1,錯誤原因存於error中
EACCESS:參數cmd為IPC_STAT,確無許可權讀取該消息隊列
EFAULT:參數buf指向無效的內存地址
EIDRM:標識符為msqid的消息隊列已被刪除
EINVAL:無效的參數cmd或msqid
EPERM:參數cmd為IPC_SET或IPC_RMID,卻無足夠的許可權執行
『伍』 請教一個關於linux進程通信消息隊列mq
在Linux中使用消息隊列
Linux提供了一系列消息隊列的函數介面來讓我們方便地使用它來實現進程間的通信。它的用法與其他兩個System V PIC機制,即信號量和共享內存相似。
1、msgget函數
該函數用來創建和訪問一個消息隊列。它的原型為:
int msgget(key_t, key, int msgflg);
與其他的IPC機制一樣,程序必須提供一個鍵來命名某個特定的消息隊列。msgflg是一個許可權標志,表示消息隊列的訪問許可權,它與文件的訪問許可權一樣。msgflg可以與IPC_CREAT做或操作,表示當key所命名的消息隊列不存在時創建一個消息隊列,如果key所命名的消息隊列存在時,IPC_CREAT標志會被忽略,而只返回一個標識符。
它返回一個以key命名的消息隊列的標識符(非零整數),失敗時返回-1.
msgsnd函數
該函數用來把消息添加到消息隊列中。它的原型為:
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
msgid是由msgget函數返回的消息隊列標識符。
msg_ptr是一個指向准備發送消息的指針,但是消息的數據結構卻有一定的要求,指針msg_ptr所指向的消息結構一定要是以一個長整型成員變數開始的結構體,接收函數將用這個成員來確定消息的類型。所以消息結構要定義成這樣:
struct my_message{
long int message_type;
/* The data you wish to transfer*/
};
msg_sz是msg_ptr指向的消息的長度,注意是消息的長度,而不是整個結構體的長度,也就是說msg_sz是不包括長整型消息類型成員變數的長度。
msgflg用於控制當前消息隊列滿或隊列消息到達系統范圍的限制時將要發生的事情。
如果調用成功,消息數據的一分副本將被放到消息隊列中,並返回0,失敗時返回-1.
『陸』 linux編程的利用消息隊列在兩個進程間通信,怎麼寫代碼,求思路,需要建立幾個消息隊列呢
首先建議你先參考 《advanced programming in the unix environment》 一書中的第15章(Interprocess communication 進程間通信)中的第7節(message queues 消息隊列)了解消息隊列的相關介面函數,比如如何創建獲取消息隊列,如何收發消息。然後就很簡單了
如果你打算兩個進程依次收消息,發消息,就像打乒乓球一樣,那麼只要一個queue,A 發消息, B 收消息並處理,然後 B 發消息, A 收並處理………… 按此次序進行下去。
更靈活的方法是兩個消息隊列 (a, b), A 進程從 隊列a收消息,向 b 發消息。 B進程從b收消息,想a發消息。