2

親プロセスにメッセージを渡すためにこのプログラムを作成しました。親プロセスが受信したメッセージを出力するようにします。私はcでのプログラミングにまったく慣れていないので、これがchar配列の読み取りまたはメッセージパッシングの問題であるかどうかはわかりません。これが私の試みです:

struct msg {
        long int    mtype;      /* message type */
        char        mtext[1028];   /* message text */
} msg;
int pid, len;
int msgflg = 0;
int msqid;
char *mymsg[1028];
size_t msgsz;
long int msgtyp;

switch(pid=fork()) //fork child process
{//Child process
case 0:
    mymsg[1] = "serving for sender\n";
    len = strlen(mymsg[1]);
    msgsnd(msqid,mymsg[1],len,msgflg);
    break;
case -1:
    printf("fork failed");
    exit(-1);
    break;
default:
    msg.mtype = 0;
    msqid = msgget(IPC_PRIVATE,msgflg); 
    wait((int *) 0);
    msgrcv(msqid,&msg,msgsz,msgtyp,IPC_NOWAIT);

    printf("%s",msg.mtext);
    msgctl(msqid, IPC_RMID, NULL);
    exit(0);
}

私の質問は、このコードをコンパイルして実行すると、送信用のメッセージが表示されないのはなぜですか?

4

3 に答える 3

3

あなたは本当に質問をしていませんが、コードで見ることができるいくつかの問題は次のとおりです。

char *mymsg[1028];
...
mymsg[1] = "serving for sender\n";

これは、文字列として扱われることを意図した へのポインタmymsgの配列です。(ちなみに、なぜ 1028 なのですか? それは重要ではありませんが、2^10 が 1024 であることを知っているためです)。ただし、この配列には、初期化されておらず、ランダムな場所を指しているポインターが含まれています。重要なことは、それらに入れたい可能性のあるメッセージに割り当てられたスペースがないことです。1028char

2 番目の問題は、C の配列がインデックス 0 で始まることです。

mymsg[0] = "serving for sender\n";

しかし、それは問題ではありません。

さらに重要なことに、を使用して C で文字列をコピーすることはできません。使用して、既に割り当てたメモリ ロケーションにコピーする=必要があります。strcpyこれを行うには、次の 2 つの方法があります。

char mymsg[1028][1028];    // if you are sure your messages fit in 1028 chars
...
mymsg[1] = malloc(strlen("serving for sender)*sizeof(char)); // sizeof(char) not really needed
strcpy(mymsg[1], "serving for sender\n");
msgsnd(msqid,mymsg[1],len,msgflg);
free(mymsg[1]);

また

char *mymsg[1028];
...
char str_to_be_printed[] = "serving for sender\n";
mymsg[1] = malloc(strlen(str_to_be_printed)*sizeof(char)); // sizeof(char) not really needed
strcpy(mymsg[1], str_to_be_printed);
msgsnd(msqid,mymsg[1],len,msgflg);
free(mymsg[1]);

編集:すでにどこかに文字列がある(「これは文字列です」という形式ではない)2番目のケースでは、ポインタを割り当てるだけで十分であり、メモリをコピーしたり割り当てたりする必要はありません。ただし、状況がこれよりも複雑で、代入とmymsg[1] = ...msgsndのコードの間にある場合は、が完了するまで元の文字列が生きていることを確認する必要がありますmsgsnd。そうしないと、ダングリング ポインターが発生し、問題が発生します。アイデアは次のとおりです。

                        +-+-+-+-+-+-+-+-+--+
str_to_be_printed ----->|A| |s|t|r|i|n|g|\0|
                        +-+-+-+-+-+-+-+-+--+
                        ^
mymsg[1]---------------/

freeのメモリをにstr_to_be_printedアクセスするmymsg[1]と、セグメンテーション違反/アクセス違反が発生します。

私が書いたコードはガイドラインを提供するためのものであり、コピーして貼り付けないでください。

于 2011-09-30T02:34:06.883 に答える
1

コードに関連する観察はほとんどありません。

  1. システム コール (エラー コードを返す関数) を使用する場合は、関数の戻り値を確認してください。使用したシステムコールの場合、errnoエラーをチェックするために使用できるエラー番号が設定されます。perrorまたはを使用strerrorしてメッセージを表示できます (Jonathan Leffler によって既に指摘されています)。
  2. 使用する前にメッセージキューを作成する必要があります (Jonathan Leffler によって再度指摘されました)。
  3. あなたは、タイプで送信char *&受信していmsgsndます。struct msgmsgrcv
  4. 使用しているが初期化されていないメッセージ キューの送受信呼び出しで渡されるサイズを設定しましたmsgsz。の値msgszを送受信したいサイズに設定します。送信中は17バイトを送信しているようですが、受信中は設定されていません。
  5. mtypeより大きい値が必要です0
  6. のタイプは でpidある必要がpid_tありますが、この場合はあまり役に立たないようです。

参照用のいくつかのコード セクション:

#include <stdio.h> /*For perror*/
...
/* Create message queue */
msqid = msgget(IPC_PRIVATE, IPC_CREAT);
if( 0 > msqid )
{
 perror("msgget");
 /* Handle error as per your requirement */
}

... 
/* Sending & receiving messages */
...
struct msg {
        long int    mtype;      /* message type */
        char        mtext[1028];   /* message text */
} sender_msg, receiver_msg;
...

size_t msgsz = 10; /* Send & receive 10 bytes, this can vary as per need. You can receive less than what was sent */
...
switch(fork())
{

case 0: /* Child */
    sender_msg.mtype = 1;
    strncpy(sender_msg.mtext,"01234567890123", 1027);
    /* Sending the whole text size */
    if ( 0 > msgsnd(msqid, &sender_msg, strlen(sender_msg.mtext),msgflg))
    {
      perror("msgsnd");
      /* Handle error as per your requirement */
    }
break;

case -1:
    perror("fork");
    exit(-1);
break;
default:
    wait((int *) 0);
    receiver_msg.mtype = 1;
    /* Receive only 10 bytes as set in msgsz */
    if( 0 > msgrcv(msqid,&receiver_msg,msgsz,msgtyp,IPC_NOWAIT))
    {
      perror("msgrcv");
      /* Error handling */
    }
    printf("%s",receiver_msg.mtext);
    if (0 > msgctl(msqid, IPC_RMID, NULL))
    {
      perror("msgctl");
      /* Handle error as per your requirement */
    }
break;

}

ここでは System V メッセージ キュー API を使用しているようです。 、 、mq_openなどmq_closeのPOSIXメッセージ キュー API を調べることができます 。 お役に立てれば!mq_sendmq_receiveman mq_overview

于 2011-09-30T04:31:10.917 に答える
1

いくつかの問題があります。

  • fork()親と子の両方がアクセスできるように、を呼び出す前にメッセージ キューを作成する必要があります。

  • メッセージ キューの権限は の 2 番目のパラメーターの下位ビットから設定されるためmsgget()、メッセージ キューの所有者に対して少なくとも読み取りと書き込みの権限を指定する必要があります。ここS_IRWXUから定数を使用できます。<sys/stat.h>

  • 文字列へのポインターを渡しmsgsnd()ていますが、実際には .xml のようなメッセージ構造体へのポインターが必要struct msgです。

  • msgrcv()失敗したかどうかを確認する必要があります。

これらの問題を修正すると、修正されたコードは次のようになります。

int pid;
int msqid;

msqid = msgget(IPC_PRIVATE, S_IRWXU);

if (msgid < 0) {
    perror("msgget");
    exit(1);
}

switch(pid=fork()) //fork child process
{//Child process
case 0:
    msg.mtype = 1;  /* Must be a positive value */
    strcpy(msg.mtext, "serving for sender\n");
    msgsnd(msqid, &msg, strlen(msg.mtext) + 1, 0);
    break;
case -1:
    printf("fork failed");
    exit(2);
    break;
default:
    wait(NULL);

    if (msgrcv(msqid, &msg, sizeof msg.mtext, 0, IPC_NOWAIT) >= 0)
        printf("%s",msg.mtext);
    else
        perror("msgrcv");

    msgctl(msqid, IPC_RMID, NULL);
    exit(0);
于 2011-09-30T05:16:14.750 に答える