进程间通信之消息队列

进程间通信

进程间通信就是在不同进程之间传播或交换信息
进程间通信(IPC,Interprocess communication)是一组编程接口,让程序员能够协调不同的进程,使之能在一个操作系统里同时运行,并相互传递、交换信息。
进程间通信主要包括

  • 管道
  • 系统IPC(包括消息队列,信号,共享存储)
  • 套接字(SOCKET)
消息

“消息”是在两台计算机间传送的数据单位。消息可以非常简单,例如只包含文本字符串;也可以更复杂,可能包含嵌入对象。

消息队列

消息被发送到队列中。“消息队列”是在消息的传输过程中保存消息的容器。
消息队列就是一个消息的链表

使用步骤

1_ 创建队列
系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。

key_t ftok( const char* fname, int id )
//fname就是你指定的文件名(已经存在的文件名),一般使用当前目录

msgget函数

int msgget(key_t key, int msgflag)

功能: 用于创建一个新的或打开一个已经存在的消息队列,此消息队列与key相对应。
第一个参数是消息队列对象的关键字(key),函数将它与已有的消息队列对象的关键字进行比较来判断消息队列对象是否已经创建
第二个参数,msgflg 控制的。它可以取下面的几个值:
 

IPC_CREAT:

  如果消息队列对象不存在,则创建之,否则进行打开操作
  

IPC_EXCL:

和IPC_CREAT 一起使用(用”|”连接),如果消息对象不存在则创建之,否则产生一个错误并返回。

如果单独使用IPC_CREAT 标志,msgget()函数要么返回一个已经存在的消息队列对象的标识符,要么返回一个新建立的消息队列对象的标识符。
如果将IPC_CREAT 和IPC_EXCL标志一起使用,msgget()将返回一个新建的消息对象的标识符,或者返回-1 如果消息队列对象已存在。
IPC_EXCL 标志本身并没有太大的意义,但和IPC_CREAT 标志一起使用可以用来保证所得的消息队列对象是新创建的而不是打开的已有的对象。
除了以上的两个标志以外,在msgflg 标志中还可以有存取权限控制符。这种控制符的意义和文件系统中的权限控制符是类似的。
2_ 获得队列

//此时msgget()的第二个参数只传IPC_CREAT
msgget(msgid, IPC_CREAT);

3_ 发送/读取消息
msgrcv()可以从消息队列中读取消息,msgsnd()将一个新的消息写入队列。
在消息队列上进行收发消息。为了发送消息,调用进程对消息队列进行写入时必须有写权能。接收消息时必须有读权能。

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_ 销毁队列

msgctl函数

int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
msgctl(msgid, IPC_RMID, 0)
//从系统内核中移走消息队列。

使用消息队列实现两个进程间的对话
//comm.h

#ifndef _COMM_H_ 
#define _COMM_H_

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>

#define CLIENT_TYPE 1
#define SERVER_TYPE 2

#define PATHNAME "."
#define IPCKEY 0x6666

struct msgbuf
{
    long mtype;
    char mtext[1024];
};


static int commMegQueue(int flag);
int creatMsgQueue();
int getMsgQueue();
int destoryMsgQueue(int msgid);
int sendMsg(int msgid, int who, char* msg);
int recvMsgQueue(int msgid, int recvType, char out[]);


#endif  
//comm.c

#include "comm.h"

static int commMegQueue(int flag)
{
    //key_t ftok( const char* fname, int id )
    key_t msgkey = ftok(PATHNAME, IPCKEY);
    if(msgkey < 0)
    {
        perror("ftok");
        return -1;
    }
    //go to here, msgkey gain succeed
    //int msgget(key_t key, int msgflag)
    int msgid = msgget(msgkey, flag); 
    if(msgid < 0)
    {
        perror("msgget");
        return -1;
    }
    //go to here, msgid gain succeed
    return msgid;
}


int creatMsgQueue()
{
    return commMegQueue(IPC_EXCL|IPC_CREAT|0666);
}
int getMsgQueue()
{
    return commMegQueue(IPC_CREAT);
}
int destoryMsgQueue(int msgid)
{
    //int msgctl ( int msgqid, int cmd, struct msqid_ds* buf );
    if(msgctl(msgid, IPC_RMID, NULL) < 0)
    {
        perror("msgctl");
        return -1;
    }
    //go to here, destoryMsgQueue succeed
    return 0;
}
int sendMsg(int msgid, int who, char* msg)
{
    //int msgsnd(int msqid, const void* msgp, size_t msgsz, int msgflg);
    struct msgbuf mybuf;
    mybuf.mtype = who;
    strcpy(mybuf.mtext, msg);
    if(msgsnd(msgid, (void*)&mybuf, sizeof(mybuf.mtext), 0) < 0)
    {
        perror("msgsnd");
        return -1;
    }
    return 0;
}
int recvMsg(int msgid, int recvType, char out[])
{
    //ssize_t msgrcv(int msqid, void* msgp, size_t msgsz, long msgtyp, int msgflg);
    struct msgbuf mybuf;
    if(msgrcv(msgid, (void*)&mybuf, sizeof(mybuf.mtext), recvType, 0) < 0)
    {
        perror("msgrcv");
        return -1;
    }
    //go to here, msgrcv succeed
    strcpy(out, mybuf.mtext);
    return 0;
}
//server.c

#include"comm.h"

int main()
{
    int msgid = creatMsgQueue();
    char buf[1024];
    while(1)
    {
        buf[0] = 0;
        if(recvMsg(msgid, CLIENT_TYPE, buf) == 0)
        {
            printf("-----------------------\n");
            printf("client say: %s", buf);
            printf("-----------------------\n");
            if(strcmp(buf, "bye") == 0)
            {
                printf("bye!\n");
                break;
            }
        }

        printf("I say:");
        fflush(stdout);
        ssize_t s = read(0, buf, sizeof(buf));
        if(s > 0)
        {
            buf[s-1] = 0;
            if (sendMsg(msgid, SERVER_TYPE, buf) == 0);
            if(strcmp(buf, "quit") == 0)
            {
                printf("Bye!\n");
                break;
            }
        }
    }

    destoryMsgQueue(msgid);

    return 0;
}
//client.c

#include"comm.h"

int main()
{
    int msgid = getMsgQueue();
    char buf[1024];
    while(1)
    {
        buf[0] = 0;
        printf("I say:");
        fflush(stdout);
        ssize_t s = read(0, buf, sizeof(buf));
        if (sendMsg(msgid, CLIENT_TYPE, buf) == 0);

        if(recvMsg(msgid, SERVER_TYPE, buf) == 0)
        {
            printf("----------------------\n");
            printf("server say: %s\n", buf);
            printf("----------------------\n");
        }
        if(strcmp(buf, "bye") == 0)
        {
            printf("I say:");
            fflush(stdout);
            ssize_t s = read(0, buf, sizeof(buf));
            if (sendMsg(msgid, CLIENT_TYPE, buf) == 0);
            break;
        }
    }
    return 0;
}

client
这里写图片描述
server

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值