消息传递C /从C中的结构打印char数组

时间:2011-09-30 01:48:19

标签: c struct message msgrcv

我创建了这个程序,将消息传递给父进程。我希望父进程打印出它收到的消息。我不确定这是否是读取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);
}

我的问题是,为什么在编译和执行此代码时,不会显示用于发送的消息?

3 个答案:

答案 0 :(得分:2)

您还没有真正提出过问题,但我可以通过代码看到的几个问题是:

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

这里有mymsg,它是1028指向char的数组,用于表示字符串。 (顺便说一下,为什么1028?不重要,但只是让你知道2 ^ 10是1024)。但是,此数组包含未初始化且指向随机位置的指针。重要的是,没有为您想要放入其中的可能消息分配空间。

第二个问题是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]会导致分段错误/访问冲突。

请注意,我写的代码只是为了给你一个指导,不要复制粘贴它。

答案 1 :(得分:1)

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

  1. 使用系统调用(任何返回任何错误代码的函数)时,请检查函数的返回值。在系统调用的情况下,您已使用将设置errno,即可用于检查错误的错误号。您可以使用perrorstrerror查看消息(已由Jonathan Leffler指出)
  2. 您需要在使用之前创建消息队列(Jonathan Leffler已经再次指出)。
  3. 您正在char *发送msgsnd&在struct msg中收到msgrcv类型。
  4. 您已设置要在消息队列中传递的大小发送&接听您正在使用msgsz但尚未初始化的电话。将msgsz的值设置为您要发送/接收的大小。虽然发送给你似乎发送了17个字节但接收它时没有设置。
  5. mtype的值应大于0
  6. pid的类型应为pid_t,无论如何,这似乎对你来说没什么好处。
  7. 一些代码部分供您参考:

    #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_closemq_sendmq_receive等。 有关消息队列概述,请参见手册页(man mq_overview
    也可以使用手册页获取有关API的信息 希望这有帮助!

答案 2 :(得分: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);