Передача сообщений в C / Печать массива char из структуры в C - PullRequest
2 голосов
/ 30 сентября 2011

Я создал эту программу для передачи сообщения родительскому процессу.Я хочу, чтобы родительский процесс распечатал полученное сообщение.Я не уверен, что это проблема чтения массива 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 ]

3 голосов
/ 30 сентября 2011

Вы на самом деле не задавали вопрос, но я вижу несколько проблем с кодом:

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 голос
/ 30 сентября 2011

У вас есть несколько проблем:

  • Перед вызовом 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);
1 голос
/ 30 сентября 2011

Есть несколько наблюдений, связанных с вашим кодом.

  1. При использовании системных вызовов (любая функция, которая возвращает любой код ошибки) проверьте возвращаемое значение функции.В случае используемых системных вызовов будет установлен errno, т. Е. Номер ошибки, который можно использовать для проверки на наличие ошибок.Вы можете использовать perror или strerror, чтобы увидеть сообщение (уже указано Джонатаном Леффлером)
  2. Вам необходимо создать очередь сообщений перед ее использованием (опять же, указал Джонатан Леффлер).
  3. Вы отправляете char * в msgsnd и получаете struct msg введите msgrcv.
  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;

}

Похоже, вы используете API очередей сообщений System V здесь, вы можете заглянуть в API очереди сообщений POSIX, например mq_open, mq_close, mq_send, mq_receive и т. Д. Для просмотра очереди сообщений см. Справочные страницы (man mq_overview)
Используйте справочные страницы также для получения информации об API.
Надеюсь, это поможет!

...