1

ここでは、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;
}
4

1 に答える 1

4

問題を解決するには、次の 2 つの方法があります。

  1. メッセージを固定長にします。
  2. メッセージの長さを含む固定長の「ヘッダー」を送信します。
  3. ターミネータを送信します。文字列には終了が含まれているように見えるためです'\0'

編集:使用方法msgsndmsgrcv

msgsnd関数はメッセージ全体が1つの連続したメモリ領域であると想定しているため、構造体の使用法は間違っています。このような例では、通常のフィールドを含む構造体を使用したり、固定長の文字列配列を使用したこの(下部) のような例を使用したりします。

構造サイズが動的な動的データも送信できます。ここでの秘訣は、小さな固定サイズの構造体を使用し、必要以上のデータを割り当てることです。

サンプルの送信者コードの一部を書き直してみましょう。

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);

受信用の上記のコードは、1 つのメッセージのみを受信します。大量のメッセージを送信する送信者と一致させたい場合は、受信コードを関数に入れ、ループで呼び出します。

免責事項:このコードはブラウザーに直接記述されており、マニュアル ページを読むだけです。私はそれをテストしていません。

于 2012-06-25T09:20:37.493 に答える