zoukankan      html  css  js  c++  java
  • 利用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 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: 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 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. 会出现死锁问题。

  • 相关阅读:
    python--模块与包
    内置函数 的总结
    迭代器 生成器 列表推导式 生成器表达式的一些总结
    函数的有用信息 带参数的装饰器 多个装饰器装饰一个函数
    函数名的应用(第一对象) 闭包 装饰器
    动态参数 名称空间 作用域 作用域链 加载顺序 函数的嵌套 global nonlocal 等的用法总结
    函数的初识 函数的返回值 参数
    文件操作 常用操作方法 文件的修改
    遍历字典的集中方法 集合的作用 以及增删查的方法
    计算机硬件的小知识
  • 原文地址:https://www.cnblogs.com/wiessharling/p/4057125.html
Copyright © 2011-2022 走看看