一、具体实现
$ ls
client client.c common.c common.h Makefile server server.c
$ cat Makefile
.PHONY:all
all: client server
client:client.c common.c
gcc $^ -o $@
server:server.c common.c
gcc $^ -o $@
.PHONY:clean
clean:
rm client server
comm.h
#pragma once
#define FILEPATH "."
#define PROJ_ID 1
typedef struct Msgbuf
{
long type;
#define MSG_TEXT_LEN 1024
char text[MSG_TEXT_LEN];
} Msgbuf;
enum Msgtype
{
/*
* server 端要做的事情
* 1、从消息队列中读取数据
* 2、根据读到的数据进行计算,生成响应数据
* 3、把响应数据写回到消息队列
*
* client 端要做的事情
* 1、从标准输入读入数据
* 2、把数据写到消息队列中
* 3、从消息队列中读取数据
* 4、把结果打印到显示器上
*
* 当前业务场景下涉及到的消息类型就只有客户端请求和服务端响应这两种
* 注意,Msgbuf.type 必须大于 0,所以才将初始值设置成 1
*/
Request = 1,
Response
};
int CreateMsg();
int OpenMsg();
int GetMsgqbytes(int msgid);
int DestroyMsg(int msgid);
int SendMsg(int msgid, char *buf, int size, int type);
int SendMsg2(int msgid, char *buf, int size, int type);
int RecvMsg(int msgid, char *buf, int size, int type);
comm.c
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#include "common.h"
int CreateMsg()
{
key_t key;
int msgid;
key = ftok(FILEPATH, PROJ_ID);
if (key < 0)
{
perror("ftok");
return -1;
}
msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);
if (msgid < 0)
{
perror("msgget");
return -1;
}
return msgid;
}
int OpenMsg()
{
key_t key;
int msgid;
key = ftok(FILEPATH, PROJ_ID);
if (key < 0)
{
perror("ftok");
return -1;
}
msgid = msgget(key, IPC_CREAT);
if (msgid < 0)
{
perror("msgget");
return -1;
}
return msgid;
}
int GetMsgqbytes(int msgid)
{
struct msqid_ds buf;
memset(&buf, sizeof(struct msqid_ds), 0x00);
if (msgctl(msgid, IPC_STAT, &buf) < 0)
{
perror("msgctl");
return -1;
}
return buf.msg_qbytes;
}
int DestroyMsg(int msgid)
{
if (msgctl(msgid, IPC_RMID, NULL) < 0)
{
perror("msgctl");
return -1;
}
return 0;
}
int SendMsg(int msgid, char *buf, int size, int type)
{
Msgbuf mbuf;
int ret;
if (size >= (int)MSG_TEXT_LEN)
{
printf("缓冲区长度不够\n");
return -1;
}
mbuf.type = type;
strcpy(mbuf.text, buf);
mbuf.text[size] = '\0';
ret = msgsnd(msgid, &mbuf, MSG_TEXT_LEN, 0); /* 阻塞 */
if (ret < 0)
{
perror("msgsnd");
return -1;
}
return 0;
}
int SendMsg2(int msgid, char *buf, int size, int type)
{
Msgbuf mbuf;
int ret;
if (size >= (int)MSG_TEXT_LEN)
{
printf("缓冲区长度不够\n");
return -1;
}
mbuf.type = type;
strcpy(mbuf.text, buf);
mbuf.text[size] = '\0';
ret = msgsnd(msgid, &mbuf, MSG_TEXT_LEN, IPC_NOWAIT); /* 非阻塞 */
if (ret < 0)
{
perror("msgsnd");
return -1;
}
return 0;
}
int RecvMsg(int msgid, char *buf, int size, int type)
{
/*(void)size;*/
Msgbuf mbuf;
ssize_t ret;
if (size < MSG_TEXT_LEN)
{
printf("缓冲区长度不够\n");
return -1;
}
memset(mbuf.text, MSG_TEXT_LEN, 0x00);
ret = msgrcv(msgid, &mbuf, MSG_TEXT_LEN, type, 0); /* 阻塞 */
if (ret < 0)
{
perror("msgrcv");
return -1;
}
strcpy(buf, mbuf.text);
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
int main()
{
int msgid;
char buf[1024];
msgid = OpenMsg();
if (msgid < 0)
return EXIT_FAILURE;
while(1)
{
ssize_t s;
while (1)
{
printf("please enter#");
fflush(stdout);
s = read(0, buf, sizeof(buf) - 1);
if (s > 0)
break;
}
SendMsg(msgid, buf, s, Request);
RecvMsg(msgid, buf, sizeof(buf), Response);
printf("server#%s", buf);
//fflush(stdout);
}
return 0;
}
service.c
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
int main()
{
int msgid;
char buf[MSG_TEXT_LEN];
msgid = CreateMsg();
if (msgid < 0)
return EXIT_FAILURE;
while(1)
{
ssize_t s;
RecvMsg(msgid, buf, sizeof(buf), Request);
printf("client#%s", buf);
//fflush(stdout);
while (1)
{
printf("please enter#");
fflush(stdout);
s = read(0, buf, sizeof(buf) - 1);
if (s > 0)
break;
};
SendMsg(msgid, buf, s, Response);
}
DestroyMsg(msgid);
return 0;
}
二、验证 MSGMNB 默认值
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "common.h"
int main()
{
int msgid, i;
char buf[1024] = {0};
msgid = CreateMsg();
if (msgid < 0)
return EXIT_FAILURE;
i = GetMsgqbytes(msgid);
if (i < 0)
return EXIT_FAILURE;
else
printf("msg_qbytes: %d\n", i);
strcpy(buf, "test data");
i = 0;
while (0 == SendMsg2(msgid, buf, strlen(buf), Request))
i++;
printf("message num: %d\n", i);
/* 暂不销毁该消息队列,利用 ipcs -q 加以验证测试结果 */
//DestroyMsg(msgid);
return 0;
}
$ ./test_msgmnb
msg_qbytes: 16384
msgsnd: Resource temporarily unavailable
message num: 16
$ ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x00000000 0 root 660 0 0
0x00000000 1 root 660 0 0
0x00000000 2 root 660 0 0
0x01026636 21 mam 666 16384 16
$