2012-06-25 26 views
1

這裏我必須使用SysV消息隊列發送和接收動態數據。想要從IPC的消息隊列中接收動態長度數據?

所以在結構領域我有動態內存分配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; 
} 
+0

爲什麼使用'strcpy','snprintf'和'strcat'?爲什麼不使用'snprintf'? –

回答

3

一對夫婦的方式來解決你的問題是:

  1. 使消息固定長度。
  2. 發送包含消息長度的固定長度「標題」。
  3. 發送終結符,因爲您似乎發送字符串包括終止'\0'

編輯:如何使用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個字符(臨時串減去一個的尺寸)。

不幸的是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); 

,用於接收上述代碼僅接收一個單個消息。如果你希望它匹配發送大量消息的發送者,那麼將接收代碼放入一個函數中,並在循環中調用它。

免責聲明:此代碼直接寫入瀏覽器,只能閱讀手冊頁。我沒有測試過它。

+0

我如何確定消息的固定長度?我想讓它變得動態。可能是receive.c文件中的問題。可以請你給我建議一些示例。 – user1089679

+0

@ user1089679編輯我的答案,包括如何處理動態消息的一些代碼。 –

+0

發件人代碼中的這個mlen怎麼樣,我認爲mlen = strlen(tmp)。我對嗎? – user1089679