IPC消息队列中msg的结构

Posted

技术标签:

【中文标题】IPC消息队列中msg的结构【英文标题】:structure of msg in IPC message queues 【发布时间】:2021-06-24 20:58:33 【问题描述】:

我在消息队列中使用消息结构的自定义定义时遇到了一些麻烦。我正在客户端和服务器之间构建一个聊天应用程序。客户端正在发送消息,而服务器正在接收消息并打印它。

这是服务器端代码 -

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>

#define MAX 200
#define SERVER 1L

typedef struct 
    long    gid;
    char    buffer[MAX];
    char    header[20];
    long    pid;
 MESSAGE;

struct msqid_ds buf;
MESSAGE msg;
int mid_server, mid_client;
key_t key1, key2;
int client_id = 0;

int main()
    //Creating a message queue
    key1 = ftok(".", 'z');
    msg.gid = 1;
    if((mid_server = msgget(key1, IPC_CREAT | 0666))<0)           
        printf("Error Creating Message Queue\n");
        exit(-1);
    

    //Receiving message from client, throws and error if input is invalid
        if(msgrcv(mid_server, &msg, MAX, SERVER, 0)<0)
        perror("msgrcv");
        exit(-1);
          
    //Server displays received message
        printf("SERVER receives: %s\n", msg.buffer);
        printf("SERVER receives---: %s\n", msg.header);
        printf("SERVER receives: %ld\n", msg.pid);                            


这是客户端 -

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <string.h>

#define MAX 200
#define SERVER 1L

typedef struct 
    long    gid;
    char    buffer[MAX];
    char    header[20];
    long    pid;
 MESSAGE;


int mid_client, mid_server;
key_t key1,key2;
MESSAGE msg;
int client_id = -1;

int main()
    //Creating a message queue
    key1 = ftok(".", 'z');
    if((mid_server = msgget(key1, IPC_CREAT | 0666))<0)             //server receives here
        printf("Error Creating Message Queue\n");
        exit(-1);
    
    printf("%d\n", mid_server);
    fgets(msg.buffer, MAX, stdin);
    msg.gid = SERVER;
    strcpy(msg.header, "msg");
    msg.pid = 2;
    if(msgsnd(mid_server, (struct MESSAGE*)&msg, sizeof(msg), IPC_NOWAIT)==-1)
        perror("msgsnd");
        exit(-1);
    
    printf("message sent\n");  

我怀疑它在服务器端打印 msg.buffer 数据没问题,但无法为 msg.header 打印任何内容,并且为 msg.pid 打印 0。这个问题是不是因为MESSAGE的结构。另外,msgsnd 中的“size_t msgsz”参数是否正确? TIA

【问题讨论】:

【参考方案1】:

根据manpage,msgsz参数是消息缓冲区的大小减去mtype。所以使用sizeof(msg) 是不正确的,会导致msgsnd() 读取到变量msg 之外。此外,这将导致服务器失败,因为服务器只期望接收MAX 字节(同样,不包括mtype)。

我会避免向struct msgbuf 添加多个成员变量,而只需添加一个成员,该成员要么是char 数组,大到足以容纳您要发送的任何数据,要么是另一个struct。例如:

#define MAX 200
#define SERVER 1L

struct payload 
    char    buffer[MAX];
    char    header[20];
    long    pid;
;

struct msgbuf 
    long gid;
    struct payload payload;
;

然后你就可以在客户端这样使用它了:

struct msgbuf msg;

msg.gid = SERVER;
fgets(msg.payload.buffer, sizeof msg.payload.buffer, stdin);
strncpy(msg.payload.header, sizeof msg.payload.header, "msg");
msg.payload.pid = 2;

if (msgsnd(mid_server, &msg, sizeof msg.payload, IPC_NOWAIT) == -1) ...

在服务器中也是这样:

struct msgbuf msg;

if (msgrcv(mid_server, &msg, sizeof msg.payload, SERVER, 0) == -1) ...

注意调用msgsnd()msgrcv() 的相似之处。

注意对齐限制,如果struct payload 中的任何成员的对齐限制大于gid 的对齐限制,则可能导致payloadgid 之后无法立即关注。 msgsz 参数应考虑到这一点。不过上面的代码应该没问题。

【讨论】:

是的,这很有效,非常感谢。被这个问题困扰了一天。

以上是关于IPC消息队列中msg的结构的主要内容,如果未能解决你的问题,请参考以下文章

IPC之——消息队列

perl 消息队列

通过 linux msg 队列传递的 C 结构间歇性失败

IPC - 消息队列(Message Queue)- 使用

IPC - 消息队列(Message Queue)- 使用

IPC - 消息队列(Message Queue)- 使用