进程间通信之消息队列(二)

消息队列
消息队列是基于消息的,且读取方式不一定是FIFO;
消息队列提供了一种从一个进程向另一个进程发送一个有类型数据块的方法;
消息队列可以实现双向通信;
消息队列是用链表实现的;

消息队列数据结构 :

   struct msqid_ds {
               struct ipc_perm msg_perm;     /* Ownership and permissions */
               time_t          msg_stime;    /* Time of last msgsnd(2) */
               time_t          msg_rtime;    /* Time of last msgrcv(2) */
               time_t          msg_ctime;    /* Time of last change */
               unsigned long   __msg_cbytes; /* Current number of bytes in
                                                queue (non-standard) */
               msgqnum_t       msg_qnum;     /* Current number of messages
                                                in queue */
               msglen_t        msg_qbytes;   /* Maximum number of bytes
                                                allowed in queue */
               pid_t           msg_lspid;    /* PID of last msgsnd(2) */
               pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
           };

内核为每一个IPC对象维护一个结构体数据结构。
IPC对象数据结构:
 struct ipc_perm {
               key_t          __key;       /* Key supplied to msgget(2) */
               uid_t          uid;         /* Effective UID of owner */
               gid_t          gid;         /* Effective GID of owner */
               uid_t          cuid;        /* Effective UID of creator */
               gid_t          cgid;        /* Effective GID of creator */
               unsigned short mode;        /* Permissions */
               unsigned short __seq;       /* Sequence number */
           };
(一)创建消息队列
    int  msgget(key_t  key,int msgflag);
(1)参数:
    ket_t   key = ftok(const char* pathname,int proj_id);
    int msgflag=(1)   IPC_CREAT   //当这个消息队列不存在时创建,当所创建的消息队列存在时打开该消息队列
                        (2)  IPC_CREAT | IPC_EXCL   //当所创建的消息队列不存在时创建,当所创建的消息队列存在时,出错返回
(2)返回值:
    msgget函数的返回值为消息队列的标识符,类似于文件描述符;
(二)给消息队列发送数据
 int msgsnd(int msgid,const char* msgp,ssize_t msgsz,int msgflag);
(1)参数:
  msgid:为msgget的返回值,消息队列标识符;
  msgp:为一个结构体数据结构:
struct msgbuf
{
    long mtype;     //数据块的类型
    char mtext[1];  //数据块,可来自定义自己要发送数据块的大小;
};

msgsz:struct msgbuf 中mtext的大小----------sizeof(mtext);
msgflag:  0表示以阻塞的方式进行数据发送;
(2)返回值:
         1)返回-1表示调用失败;
         2)如果调用成功,则返回发送数据的字节数;
(三)接收消息队列中的数据
(1)参数:
ssize_t  msgrcv(int msgid,void *msgp,ssize_t msgsz,long msgtyp,int msgflag);
msgid:接收哪一个消息队列的数据,消息队列标识符;
msgp:存放数据的缓冲区;
msgsz:接收数据缓冲区的大小;
msgtyp:所接收的数据的类型;
msgflag:0表示以阻塞的方式接收数据;
(2)返回值:
       失败返回-1;
       成功返回接收到数据的字节数;
(四)删除消息队列
 int msgctl(int msqid, int cmd, struct msqid_ds *buf);
(1)参数:
  msgid:消息队列标识符,表示要删除哪一个消息队列;
  cmd:IPC_RMID表示删除;
  buf:NULL
(2)返回值:
 删除成功返回0;
删除失败返回-1;
common.h
#ifndef _COMMON_H
#define _COMMON_H
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#include<unistd.h>
#define PATHNAME "/home/cm/code"
#define PROJ_ID 0x6666
#define SERVER_TYPE 1
#define CLIENT_TYPE 2
struct msgbuf
{
    long mtype;
    char mtext[1024];
};

int commonCreat_messageQueue(int flags);
int Get_messageQueue();
int Creat_messageQueue();
int Delete_messageQueue(int msg_id);
int sendData_To_messageQueue(int msg_id,int sendType,char* msg);
int receiveData_Of_messageQueue(int msg_id,int recvType,char *out);

#endif
common.c

#include"common.h"

int commonCreat_messageQueue(int flags)
{
    key_t key = ftok(PATHNAME,PROJ_ID);
    if(key < 0)
    {
        perror("ftok");
        return -1;
    }
    int msg_id =  msgget(key,flags);
    if(msg_id < 0)
    {
        perror("msgget");
        return -2;
    }
    return msg_id;
}

int Creat_messageQueue()
{
    int msg_id = commonCreat_messageQueue(IPC_CREAT | IPC_EXCL|0666);
    return msg_id;
}


int Get_messageQueue()
{
    int msg_id = commonCreat_messageQueue(IPC_CREAT);
    return msg_id;
}

int Delete_messageQueue(int msg_id)
{
    if( msgctl(msg_id,IPC_RMID,NULL)<0)
    {
        return -1;
    }
    return 0;
}

//send data
int sendData_To_messageQueue(int msg_id,int sendType,char* msg)
{
    struct msgbuf buf;
    buf.mtype = sendType;
    strcpy(buf.mtext,msg);
    int snd_msg = msgsnd(msg_id,(void*)&buf,sizeof(buf.mtext),0);
    if(snd_msg <0)
    {
        perror("msgsng");
        return -3;
    }
    return 0;;
}

//receive data
int receiveData_Of_messageQueue(int msg_id,int recvType,char* out)
{
    struct msgbuf buf;
    ssize_t s = msgrcv(msg_id,(void*)&buf,sizeof(buf.mtext),recvType,0);
    if(s < 0)
    {
        perror("msgrcv");
        return -4;
    }
    strcpy(out,buf.mtext);
    return 0;
}

server.c

//server-------------first receive data and next to send data
#include"common.h"
int main()
{
    char buf[1024];
    int msg_id = Creat_messageQueue();
    while(1)
    {
        //receive data
        receiveData_Of_messageQueue(msg_id,CLIENT_TYPE,buf);
        printf("Client#%s\n",buf);
        //send data
        printf("Please Enter# ");
        fflush(stdout);
        ssize_t s = read(0,buf,sizeof(buf)-1);
        if(s>0) //read success
        {
            buf[s-1] = 0;
            sendData_To_messageQueue(msg_id,SERVER_TYPE,buf);
            printf("send done,wait receive........\n");
        }
    }
    return 0;
    Delete_messageQueue(msg_id);
}
client.c

//client---------------first send data and next is to receive data
#include"common.h"
int main()
{
   int msg_id = Get_messageQueue();
   //read data from stdin and send to msgqueue

   char buf[1024];
   while(1)
   {
     printf("Please Enter# ");
     fflush(stdout);
     ssize_t s = read(0,buf,sizeof(buf)-1);
     if(s<0)
     {
         //read failed
         perror("read");
     }
     buf[s-1] = 0;
     sendData_To_messageQueue(msg_id,CLIENT_TYPE,buf);
     printf("send done,wait receive............\n");

     receiveData_Of_messageQueue(msg_id,SERVER_TYPE,buf);
     printf("Server# %s\n",buf);
   }
    return 0;
}

Makefile:

.PHONY:all
all:client server
client:client.c common.c
    gcc -o $@ $^
server:server.c common.c
    gcc -o $@ $^
.PHONY:clean
clean:
    rm -rf server client


作者水平有限,若有问题,请留言,谢谢!!!



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值