1.單個消息隊列實現回射服務器
-
隊列複用功能:客戶端——>服務器端,服務器端——>客戶端端
-
客戶1:只接收類型爲1234的消息,客戶2只接收類型爲9876的消息
-
單個隊列的死鎖現象: 當多個客戶端往發送請求,將隊列堵滿了,服務器不能夠應答,客戶端在等待服務器回射數據回來,此時會產生死鎖。
-
eg服務端程序:NetworkProgramming-master (1)\NetworkProgramming-master\P27msgsrv.c
//
// Created by wangji on 19-8-12.
//
// p25 system v消息隊列(三)回射服務器端
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>//memset函數的頭文件
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0);
#define MSGMAX 8192
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[msgbuf]; /* message data */
};
void echo_srv(int msgid)
{
struct msgbuf msg;
int n;
int type;
memset(&msg, 0, sizeof(msgbuf));
while (1)
{
if ((n = msgrcv(msgid, &msg, MSGMAX, 1, 0)) < 0)//不停的接收類型=1的消息,0表示以阻塞的方式接收
{
ERR_EXIT("msgsnd");
}
//解析的來自客戶端的pid+回射行line
type = *((int*)msg.mtext);//取出前4個字節
msg.mtype = type;
//前4個字節是pid
fputs(msg.mtext+4, stdout);
if (msgsnd(msgid, &msg, n, 0) < 0)
{
ERR_EXIT("msgsnd");
}
//memset(&msg, 0, sizeof(msgbuf));
}
}
int main(int argc, char** argv)
{
int msgid;
msgid = msgget(1234, IPC_CREAT|0666);
if (msgid == -1)
{
ERR_EXIT("msgget");
}
echo_srv(msgid);
return 0;
}
- eg客戶端程序:NetworkProgramming-master (1)\NetworkProgramming-master\P27msgcli.c
//
// Created by wangji on 19-8-12.
//
// p25 system v消息隊列(三)回射客戶端
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0);
#define MSGMAX 8192
#define MSGMAX 8192
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[MSGMAX]; /* message data */
};
int echocli(int msgid)
{
struct msgbuf msg;
memset(&msg, 0, sizeof(msgbuf));
int pid = getpid();
msg.mtype = 1;//客戶端給服務器段發送的消息類型總是=1
*((int*)msg.mtext) = pid;//msg.mtext前4個字節是pid
int n;
//msg.mtext + 4,表示前4個字節是pid
while (fgets(msg.mtext + 4, MSGMAX, stdin) != NULL)//不停的從鍵盤中獲取1行數據
{
//msgsnd(msgid, &msg,4 + strlen(4+msg.mtext), 0)也對,客戶端發送的是:pid+回射行line
if (msgsnd(msgid, &msg, sizeof(long) + strlen(msg.mtext), 0) < 0)
{
ERR_EXIT("msgsnd");
}
//前4個字節不需要清空,用以保存pid
memset(msg.mtext+4, 0, sizeof(msg.mtext + 4));
if ((n = msgrcv(msgid, &msg, MSGMAX, pid, 0)) < 0)//接收類型是pid的消息
{
ERR_EXIT("msgsnd");
}
fputs(msg.mtext + 4, stdout);
memset(msg.mtext + 4, 0, sizeof(msg.mtext + 4));
}
}
int main(int argc, char** argv)
{
int msgid;
msgid = msgget(1234, 0);
if (msgid == -1)
{
ERR_EXIT("msgget");
}
echocli(msgid);
return 0;
}
- 測試結果如下:
2.多個隊列解決單個隊列的死鎖問題
- 多個隊列解決死鎖現象
(1)當一個客戶端創建時,同時創建一個私有的隊列;
(2)當客戶端往服務器端發送消息時,會將私有隊列的標識符傳遞給服務器端,以便服務器端能夠向私有隊列填充數據;
(3)服務器端收到消息後,會fork一個子進程來將消息回射到客戶端,子進程將消息填充到私有隊列中;