利用System V消息队列实现回射客户/服务器

时间:2023-03-09 19:09:10
利用System V消息队列实现回射客户/服务器

一、介绍

在学习UNIX网络编程 卷1时,我们当时可以利用Socket套接字来实现回射客户/服务器程序,但是Socket编程是存在一些不足的,例如:

1. 服务器必须启动之时,客户端才能连上服务端,并与服务端进行通信;

2. 利用套接口描述符进行通信,必须知道对端的IP与端口。

二、相关函数介绍

下面,我们利用System V消息队列来实现进程间的通信:

首先,我们先来了解一下下面几个函数:

1. msgget: 该函数用于打开或创建消息队列,其作用相当与文件操作函数open。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> int msgget(key_t key, int msgflg);

2. msgsnd:消息发送函数

3. msgrcv:消息接收函数

       #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);

4. struct msgbuf

 struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[]; /* message data */
};

mtype 消息类型

mtext 消息内容

三、实现原理

  服务器端:只接收类型为1的消息,接收完毕之后,取出mtext的前四个字节并存储为client_pid,并将消息类型mtype修改为client_pid;

  客户端:只发送类型为1的消息,即将 mtype 置为1,并将mtext的前四个字节的内容设为自身的进程id,即pid.

四、编程实现如下:

客户端:

/*************************************************************************
> File Name: echocli.c
> Author: ma6174
> Mail: ma6174@163.com
> Created Time: Tue 28 Oct 2014 11:25:48 AM HKT
************************************************************************/ #include<stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while()
#define MSGMAX 8192 struct msgbuf
{ long mtype; /* type of message */
char mtext[MSGMAX]; /* message text */
}; void echo_cli(int msgid)
{
int pid = getpid();
int n; struct msgbuf msg;
memset(&msg, , sizeof(msg));
msg.mtype = ;
*((int*)msg.mtext) = pid; while(fgets(msg.mtext + , MSGMAX, stdin) != NULL)
{
msg.mtype = ;
if(msgsnd(msgid, &msg, + strlen(msg.mtext + ), IPC_NOWAIT) < )
ERR_EXIT("msgsnd");
memset(msg.mtext + , , MSGMAX - );
if((n = msgrcv(msgid, &msg, MSGMAX, pid, )) < )
ERR_EXIT("msgrcv");
fputs(msg.mtext + , stdout);
memset(msg.mtext + , , MSGMAX - );
}
} int main(int argc, char **argv)
{
int msgid;
msgid = msgget(, );//open
if(msgid == -)
ERR_EXIT("msgget"); echo_cli(msgid);
return ;
}

服务端:

/*************************************************************************
> File Name: echosrv.c
> Author: ma6174
> Mail: ma6174@163.com
> Created Time: Tue 28 Oct 2014 11:25:58 AM HKT
************************************************************************/ #include<stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() #define MSGMAX 8192 struct msgbuf
{
long mtype; /* type of message */
char mtext[MSGMAX]; /* message text */
}; void echo_srv(int msgid)
{
int n;
struct msgbuf msg;
memset(&msg, , sizeof(msg));
while()
{
//only recv the message of type = 1
if((n = msgrcv(msgid, &msg, MSGMAX, , )) < )
{
ERR_EXIT("msgrcv");
} fputs(msg.mtext + , stdout);
//client pid
int pid;
pid = *((int*)msg.mtext); //回射
msg.mtype = pid;//type
msgsnd(msgid, &msg, n, );
memset(&msg, , sizeof(msg));
}
} int main(int argc, char **argv)
{
int msgid;
msgid = msgget(, IPC_CREAT | );
if(msgid == -)
{
ERR_EXIT("msgget");
}
echo_srv(msgid);
return ;
}

存在问题:

1. 不同主机间不同的进程无法进行通信。

2. 消息的长度受到限制MSGMAX

3. 消息的数量收到限制MSGMNB

4. 会出现死锁问题。