Передача сообщений на C / печать массива символов из структуры на C

#c #struct #message #msgrcv

#c #структура #Сообщение #msgrcv

Вопрос:

Я создал эту программу для передачи сообщения родительскому процессу. Я хочу, чтобы родительский процесс распечатал полученное сообщение. Я не уверен, связано ли это с чтением массива символов или передачей сообщений, поскольку я новичок в программировании на 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 sendern";
    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,amp;msg,msgsz,msgtyp,IPC_NOWAIT);

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

Мой вопрос в том, почему сообщение, предназначенное для отправки, не отображается при компиляции и выполнении этого кода?

Комментарии:

1. Вероятно, вам следует создать очередь сообщений перед разветвлением. Вы не можете использовать неинициализированный msqid и ожидать отправки сообщения. Вы также должны тщательно проверять статус возврата системных вызовов; вам нужно знать, когда что-то идет не так.

Ответ №1:

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

 char *mymsg[1028];
...
mymsg[1] = "serving for sendern";
  

Здесь у вас есть mymsg массив 1028 указателей на char , который предназначен для обработки как строка. (Кстати, почему 1028? Не то чтобы это имело значение, но просто чтобы вы знали, что 2 ^ 10 равно 1024). Однако этот массив содержит указатели, которые не инициализированы и указывают на случайные местоположения. Важно то, что для возможного сообщения, которое вы хотите в них поместить, не выделено места.

Вторая проблема заключается в том, что массивы в C начинаются с индекса 0, поэтому вы, вероятно, хотели написать

 mymsg[0] = "serving for sendern";
  

Однако это не имеет значения.

Что еще более важно, вы не можете копировать строки на 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 sendern");
msgsnd(msqid,mymsg[1],len,msgflg);
free(mymsg[1]);
  

или

 char *mymsg[1028];
...
char str_to_be_printed[] = "serving for sendern";
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. Я думаю, что в коде = используется для присвоения указателя на массив символов строке, которая будет создана в разделе памяти, доступном только для чтения. OP ничего не копирует. Назначение кажется законным.

2. Я учел это и отредактирую свой ответ. Однако, поскольку OP сказал, что он новичок в C, я подумал, что, возможно, было бы неплохо убедиться, что он это понял.

3. @matt_bro вы получили ответ на свой вопрос? Вам нужна дополнительная помощь?

Ответ №2:

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

  1. При использовании системных вызовов (любой функции, которая возвращает любой код ошибки) проверьте возвращаемое значение функции. В случае использованных вами системных вызовов будет установлен errno номер ошибки, который можно использовать для проверки на наличие ошибки. Вы можете использовать perror или strerror , чтобы просмотреть сообщение (уже указано Джонатаном Леффлером)
  2. Перед его использованием необходимо создать очередь сообщений (на это снова указал Джонатан Леффлер).
  3. Вы отправляете char * msgsnd и получаете struct msg ввод msgrcv .
  4. Вы установили размер, который будет передаваться в вызовах отправки и приема очереди сообщений, для которых вы используете msgsz , но неинициализированы. Установите значение msgsz в размере, который вы хотите отправить / получить. При отправке вы, кажется, отправляете 17 байт, но при получении он не установлен.
  5. mtype должно иметь значение больше 0 .
  6. Тип for 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 amp; receiving messages */
...
struct msg {
        long int    mtype;      /* message type */
        char        mtext[1028];   /* message text */
} sender_msg, receiver_msg;
...

size_t msgsz = 10; /* Send amp; 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, amp;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,amp;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.
Надеюсь, это поможет!

Ответ №3:

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

  • Перед вызовом необходимо создать очередь сообщений 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 sendern");
    msgsnd(msqid, amp;msg, strlen(msg.mtext)   1, 0);
    break;
case -1:
    printf("fork failed");
    exit(2);
    break;
default:
    wait(NULL);

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

    msgctl(msqid, IPC_RMID, NULL);
    exit(0);