利用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: [email protected]
    > 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 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, 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: [email protected]
    > 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 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, 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. 会出现死锁问题。

时间: 2024-10-24 04:21:01

利用System V消息队列实现回射客户/服务器的相关文章

Linux IPC实践(6) --System V消息队列(3)

消息队列综合案例 消息队列实现回射客户/服务器 server进程接收时, 指定msgtyp为0, 从队首不断接收消息 server进程发送时, 将mtype指定为接收到的client进程的pid client进程发送的时候, mtype指定为自己进程的pid client进程接收时, 需要将msgtyp指定为自己进程的pid, 只接收消息类型为自己pid的消息; // client/server进程接收/发送的数据结构 const int MSGMAX = 8192; struct msgBuf

System V消息队列(2)

msgsnd函数 功能:把一条消息添加到消息队列中 原型 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 参数 msgid: 由msgget函数返回的消息队列标识码 msgp:是一个指针,指针指向准备发送的消息, msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型 msgflg:控制着当前消息队列满或到达系统上限时将要发生的事情 返回值:成功返回0:失败返回-1 msgs

进程间通信 System V 消息队列

1.msgget (key_t ket,int flag) ; //创建一个新的消息队列或者访问一个已存在的消息队列 2.msgsnd(int msid, const void *ptr ,size_t length ,int flag ) // 发送 3.msgrcv() //读 4.msgctl(int msid , int cmd ,struct  msqid_ds *buff )//  cmd 提供删除,设置,返回当前 tips : 1.客户端服务端例子 服务端创建两个消息队列,A,B,

细说linux IPC(十):system V 消息队列

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] system V消息队列和posix消息队列类似,linux系统这两种消息队列都支持.先来看一下system V消息队列相关操作及其函数. msgget()函数创建一个消息队列或打开一个消息队列. #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h&

Linux IPC实践(5) --System V消息队列(2)

消息发送/接收API msgsnd函数 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 参数 msgid: 由msgget函数返回的消息队列标识码, 也可以是通过ipcs命令查询出来的一个已经存在的消息队列的ID号 msgp:是一个指针,指针指向准备发送的消息, msgsz:是msgp指向的消息长度, 注意:这个长度不含保存消息类型的那个long int长整型 msgflg:控制着当前消息队列满或到达系统上限时

LINUX学习:System V消息队列

介绍: 1.消息队列提供了一个从一个进程向另外一个进程发送数据块的方法 2.每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值 3.消息队列也有管道一样的不足,就是每个消息最大的长度是有上限的(MSGMAX),每个消息队列 的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也是有一个上限的.   每个IPC对象都在内核维护着一个数据结构, 消息不同于刘模式,消息是有边界的,消息都是被打包在一个一个的数据包里的. 那么我们看下消息队列结构:       消息队列有4

Linux IPC实践(4) --System V消息队列(1)

消息队列概述 消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法(仅局限于本机); 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值. 消息队列也有管道一样的不足: (1)每个消息的最长字节数的上限(MSGMAX); (2)系统中消息队列的总条数也有一个上限(MSGMNI); (3)每个消息队列所能够保存的总字节数是有上限的(MSGMNB) . 查看系统限制 cat /proc/sys/kernel/msgmax  #最大消息长度限制 cat /proc/sys

System V 消息队列

3.1 概述 消息队列结构: struct msqid_ds { struct ipc_perm msg_perm; //权限结构 struct msg *msg_first; //队列中第一个消息 struct msg *msg_last; //队列中最后一个消息 msglen_t msg_cbytes; //队列中当前消息总字节数 msglen_t msg_qbytes; //队列中最大消息总字节数 msgqnum_t msg_qnum; //队列中当前消息数 pid_t msg_lspid

Linux进程间通信——使用System V 消息队列

消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法. 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构.我们可以通过发送消息来避免命名管道的同步和阻塞问题.但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制. Linux用宏MSGMAX和MSGMNB来限制一条消息的最大长度和一个队列的最大长度. 在Linux中使用消息队列 Linux提供了一系列消息队列的函数接口来让我们方便地使用它来实现进程间的通信. msgget 函数 创建和访问一个