首页 > 代码库 > 利用System V消息队列实现回射客户/服务器

利用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[1];    /* 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(0)#define MSGMAX 8192struct 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, 0, sizeof(msg));    msg.mtype = 1;    *((int*)msg.mtext) = pid;    while(fgets(msg.mtext + 4, MSGMAX, stdin) != NULL)    {        msg.mtype = 1;        if(msgsnd(msgid, &msg, 4 + strlen(msg.mtext + 4), IPC_NOWAIT) < 0)            ERR_EXIT("msgsnd");        memset(msg.mtext + 4, 0, MSGMAX - 4);        if((n = msgrcv(msgid, &msg, MSGMAX, pid, 0)) < 0)            ERR_EXIT("msgrcv");        fputs(msg.mtext + 4, stdout);        memset(msg.mtext + 4, 0, MSGMAX - 4);    }}int main(int argc, char **argv){    int msgid;    msgid = msgget(1234, 0);//open    if(msgid == -1)        ERR_EXIT("msgget");    echo_cli(msgid);    return 0;}

 

 

服务端:

/*************************************************************************    > 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(0)#define MSGMAX 8192struct msgbuf{    long mtype; /* type of message */    char mtext[MSGMAX]; /* message text */};void echo_srv(int msgid){    int n;    struct msgbuf msg;    memset(&msg, 0, sizeof(msg));    while(1)    {        //only recv the message of type = 1         if((n = msgrcv(msgid, &msg, MSGMAX, 1, 0)) < 0)        {            ERR_EXIT("msgrcv");        }        fputs(msg.mtext + 4, stdout);        //client pid        int pid;        pid = *((int*)msg.mtext);        //回射        msg.mtype = pid;//type        msgsnd(msgid, &msg, n, 0);        memset(&msg, 0, sizeof(msg));    }}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;}

 

 

存在问题:

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

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

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

4. 会出现死锁问题。

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