#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:
Есть несколько замечаний, связанных с вашим кодом.
- При использовании системных вызовов (любой функции, которая возвращает любой код ошибки) проверьте возвращаемое значение функции. В случае использованных вами системных вызовов будет установлен
errno
номер ошибки, который можно использовать для проверки на наличие ошибки. Вы можете использоватьperror
илиstrerror
, чтобы просмотреть сообщение (уже указано Джонатаном Леффлером) - Перед его использованием необходимо создать очередь сообщений (на это снова указал Джонатан Леффлер).
- Вы отправляете
char *
msgsnd
и получаетеstruct msg
вводmsgrcv
. - Вы установили размер, который будет передаваться в вызовах отправки и приема очереди сообщений, для которых вы используете
msgsz
, но неинициализированы. Установите значениеmsgsz
в размере, который вы хотите отправить / получить. При отправке вы, кажется, отправляете 17 байт, но при получении он не установлен. mtype
должно иметь значение больше0
.- Тип 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);