想从IPC中的消息队列接收动态长度数据吗?

时间:2012-06-25 09:13:53

标签: c ipc message-queue

在这里,我必须使用SysV消息队列发送和接收动态数据。

所以在结构领域我有动态内存分配char *,因为它的大小可能会有所不同。

那么如何才能在接收方收到此类消息。

请告诉我如何使用邮件队列发送动态长度的数据。

我遇到问题,我在下面发布了我的代码。

send.c

/*filename   : send.c
 *To compile : gcc send.c -o send
 */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct my_msgbuf {
    long mtype;
    char *mtext;
};

int main(void)
{
    struct my_msgbuf buf;
    int msqid;
    key_t key;
    static int count = 0;
    char temp[5];
    int run = 1;
    if ((key = ftok("send.c", 'B')) == -1) {
        perror("ftok");
        exit(1);
    }

    printf("send.c Key is = %d\n",key);

    if ((msqid = msgget(key, 0644 | IPC_CREAT)) == -1) {
        perror("msgget");
        exit(1);
    }

    printf("Enter lines of text, ^D to quit:\n");

    buf.mtype = 1; /* we don't really care in this case */
    int ret = -1;
    while(run) {
        count++;
        buf.mtext = malloc(50);
        strcpy(buf.mtext,"Hi hello test message here");
        snprintf(temp, sizeof (temp), "%d",count);
        strcat(buf.mtext,temp);
        int len = strlen(buf.mtext);
        /* ditch newline at end, if it exists */
        if (buf.mtext[len-1] == '\n') buf.mtext[len-1] = '\0';
        if (msgsnd(msqid, &buf, len+1, IPC_NOWAIT) == -1) /* +1 for '\0' */
        perror("msgsnd");
        if(count == 100)
            run = 0;
        usleep(1000000);
    }

    if (msgctl(msqid, IPC_RMID, NULL) == -1) {
        perror("msgctl");
        exit(1);
    }

    return 0;
}

receive.c

/* filename   : receive.c
 * To compile : gcc receive.c -o receive
 */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct my_msgbuf {
    long mtype;
    char *mtext;
};

int main(void)
{
    struct my_msgbuf buf;
    int msqid;
    key_t key;

    if ((key = ftok("send.c", 'B')) == -1) {  /* same key as send.c */
        perror("ftok");
        exit(1);
    }

    if ((msqid = msgget(key, 0644)) == -1) { /* connect to the queue */
        perror("msgget");
        exit(1);
    }

    printf("test: ready to receive messages, captain.\n");

    for(;;) { /* receive never quits! */
        buf.mtext = malloc(50);
        if (msgrcv(msqid, &buf, 50, 0, 0) == -1) {
            perror("msgrcv");
            exit(1);
        }
        printf("test: \"%s\"\n", buf.mtext);
    }

    return 0;
}

1 个答案:

答案 0 :(得分:3)

解决问题的几种方法是:

  1. 使邮件固定长度。
  2. 发送包含邮件长度的固定长度“标题”。
  3. 发送终结符,因为您似乎发送字符串包括终止'\0'
  4. 修改:如何使用msgsndmsgrcv

    您对结构和msgsnd的使用是错误的,因为函数期望整个消息是一个连续的内存区域。 this等示例使用包含普通字段的结构,或者使用固定长度字符串数组的this(在底部)。

    您也可以发送结构大小为动态的动态数据。这里的技巧是使用一个小的固定大小的结构,并分配比所需更多的数据。

    让我们重写部分示例发件人代码:

    struct my_msgbuf {
        long   mtype;     /* Message type, must be > 0 */
        char   mtext[1];  /* Some compilers allow `char mtext[0]` */
    };
    
    /* ... */
    
    
    int count = 0;
    while (count < 100) {
        count++;
    
        /* Put string in a temporary place */
        char tmp[64];
        snprintf(tmp, sizeof(tmp), "Hi hello test message here %d", count);
    
        /* +1 for the terminating '\0' */
        size_t msgsz = strlen(tmp) + 1;
    
        /* Allocate structure, and memory for the string, in one go */
        struct my_msgbuf *buf = malloc(sizeof(struct my_msgbuf) + msgsz);
    
        /* Set up the message structure */
        buf->mtype = 1;
        memcpy(buf->mtext, tmp, msgsz);
    
        /* And send the message */
        msgsnd(msgid, buf, msgsz, IPC_NOWAIT);
    
        /* Remember to free the allocated memory */
        free(buf);
    }
    

    上面的代码处理动态字符串的发送,只要小于63个字符(临时字符串的大小减去1)。

    不幸的是msgrcv并不真正支持接收动态大小的数据。不使用MSG_NOERROR标志,检查错误E2BIG,然后使用realloc获取更大的邮件缓冲区,可以帮助您。

    收到这样的东西:

    /* Should start with larger allocation, using small just for example */
    size_t msgsz = 8;
    struct my_msgbuf *buf = NULL;
    
    for (;;) {
        /* Allocate if `buf`  is NULL, otherwise reallocate */
        buf = realloc(buf, msgsz);
    
        /* Receive message */
        ssize_t rsz = msgrcv(msgid, buf, msgsz, 1, 0);
    
        if (rsz == -1) {
            if (errno == E2BIG)
                msgsz += 8;  /* Increase size to reallocate and try again */
            else {
                perror("msgrcv");
                break;
            }
        } else {
            /* Can use `buf->mtext` as a string, as it already is zero-terminated */
            printf("Received message of length %d bytes: \"%s\""\n", rsz, buf->mtext);
            break;
        }
    }
    
    if (buf != NULL)
        free(buf);
    

    以上接收代码只接收一条消息。如果你希望它匹配发送大量消息的发送者,那么将接收代码放在一个函数中,然后循环调用它。

    免责声明:此代码直接在浏览器中编写,只读取手册页。我还没有测试过。