2

我创建了这个程序来将消息传递给父进程。我希望父进程打印出它收到的消息。我不确定这是否是读取 char 数组或消息传递的问题,因为我对 c 编程很陌生。这是我的尝试:

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

第二个问题是 C 中的数组从索引 0 开始,所以你可能打算写

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

不过那没关系。

更重要的是,您不能在 C 中使用 复制字符串=,您应该使用strcpy并复制到您已经分配的内存位置。这里有两种方法:

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

编辑:在第二种情况下,您已经在某处拥有字符串(而不是以“这是一个字符串”的形式),分配指针就足够了,您无需复制或分配内存。但是,如果您的情况比这更复杂,并且在分配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

你有几个问题:

  • 调用前需要先创建消息队列fork(),让父子都可以访问;

  • 消息队列的权限是从 的第二个参数的低位开始设置的msgget(),所以至少需要为消息队列的所有者指定读写权限。S_IRWXU您可以从<sys/stat.h>这里使用常量;

  • 您正在传递msgsnd()一个指向字符串的指针,但它实际上需要一个指向消息结构的指针,例如您的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 回答
1

与您的代码相关的观察很少。

  1. 当您使用系统调用(任何返回任何错误代码的函数)时,请检查函数的返回值。在您使用的系统调用的情况下,将设置errnoie 可用于检查错误的错误编号。您可以使用perrorstrerror查看消息(已由 Jonathan Leffler 指出)
  2. 您需要在使用它之前创建消息队列(Jonathan Leffler 已经再次指出)。
  3. 您正在发送char *msgsnd接收struct msg类型msgrcv
  4. msgsz您已设置要在您正在使用但未初始化的消息队列发送和接收调用中传递的大小。将值设置为msgsz您要发送/接收的大小。发送时您似乎发送了 17 个字节,但接收时未设置。
  5. mtype应该有一个大于 的值0
  6. 键入 for pidshould be 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,您可以查看 POSIX 消息队列 API,如、 、mq_openmq_close。有关消息队列概述,请参阅手册页 ( ) 也使用手册页了解有关 API 的信息。 希望这可以帮助!mq_sendmq_receiveman mq_overview

于 2011-09-30T04:31:10.917 回答