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. 会出现死锁问题。

  • 相关阅读:
    小程序升级实时音视频录制及播放能力,开放 Wi-Fi、NFC(HCE) 等硬件连接功能
    12306网站将新增微信通知方式
    QQ-AR助人教版小学英语“动”起来
    【福利】公众平台全面开放原创功能
    12月微信的新规来了
    微信公众平台原创声明和留言功能面向微信认证帐号公测
    微信公众平台支持开通微信小店小程序了
    腾讯2017年第三季度财报:微信广告收入大幅增长
    2017微信数据报告 截至9月日登录用户超9亿日发送消息380亿次
    iOS版微信6.5.21发布 适配iPhone X
  • 原文地址:https://www.cnblogs.com/wiessharling/p/4057125.html
Copyright © 2011-2022 走看看