C中的消息传递/从C中的结构打印字符数组
我创建这个程序是为了向父进程传递消息。我希望父进程打印出它收到的消息。我不确定这是否与读取字符数组或消息传递有关,因为我对c语言编程非常陌生。以下是我的尝试:C中的消息传递/从C中的结构打印字符数组,c,struct,message,msgrcv,C,Struct,Message,Msgrcv,我创建这个程序是为了向父进程传递消息。我希望父进程打印出它收到的消息。我不确定这是否与读取字符数组或消息传递有关,因为我对c语言编程非常陌生。以下是我的尝试: struct msg { long int mtype; /* message type */ char mtext[1028]; /* message text */ } msg; int pid, len; int msgflg = 0; int msqid; char
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);
}
我的问题是,为什么在编译和执行此代码时没有显示用于发送的消息?您还没有真正提出问题,但我可以看到代码中的几个问题是:
char *mymsg[1028];
...
mymsg[1] = "serving for sender\n";
这里有一个mymsg
,它是指向char
的1028
指针的数组,可以将其视为字符串。(顺便问一下,为什么是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]);
或
编辑:在第二种情况下,您已经在某个地方有了字符串(而不是以“thisastring”的形式),分配指针就足够了,您不需要复制或分配内存。但是,如果您的情况比这更复杂,并且在分配mymsg[1]=…
和msgsnd
之间还有其他代码,则必须确保原始字符串保持活动状态,直到msgsnd
完成。否则,您将有一个悬空的指针,这将给您带来问题。我的想法是:
+-+-+-+-+-+-+-+-+--+
str_to_be_printed ----->|A| |s|t|r|i|n|g|\0|
+-+-+-+-+-+-+-+-+--+
^
mymsg[1]---------------/
如果释放要打印的str\u的内存
,访问mymsg[1]
将导致分段错误/访问冲突
请注意,我编写的代码只是给您一个指导原则,不要复制粘贴它。与您的代码相关的观察很少
使用系统调用(返回任何错误代码的任何函数)时,请检查函数的返回值。对于您使用的系统调用,将设置errno
,即可用于检查错误的错误号。您可以使用perror
或strerror
查看消息(Jonathan Leffler已经指出)
您需要在使用消息队列之前创建它(Jonathan Leffler已经指出)
您正在msgsnd
中发送char*
,并在msgrcv
中键入struct msg
您已经设置了要在消息队列发送和接收呼叫中传递的大小,您正在使用msgsz
,但尚未初始化。将msgsz
的值设置为要发送/接收的大小。发送时,您似乎在发送17个字节,但在接收时,未设置该字节
mtype
的值应大于0
pid
的类型应该是pid\u 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;
}
#包括/*用于perror*/
...
/*创建消息队列*/
msqid=msgget(IPC_PRIVATE,IPC_CREAT);
如果(0>msqid)
{
佩罗尔(“msgget”);
/*根据您的要求处理错误*/
}
...
/*发送和接收消息*/
...
结构味精{
long int mtype;/*消息类型*/
字符多行文字[1028];/*消息文字*/
}发送方消息,接收方消息;
...
大小\u t msgsz=10;/*发送和接收10个字节,可根据需要更改。您可以收到少于已发送的内容*/
...
开关(fork())
{
案例0:/*儿童*/
发送方\ u msg.mtype=1;
strncpy(发送方消息多行文字,“01234567890123”,1027);
/*发送整个文本大小*/
如果(0>msgsnd(msqid和sender_msg,strlen(sender_msg.mtext),msgflg))
{
perror(“msgsnd”);
/*根据您的要求处理错误*/
}
打破
案例1:
佩罗尔(“福克”);
出口(-1);
打破
违约:
等待((int*)0);
接收器\u msg.mtype=1;
/*仅接收msgsz中设置的10个字节*/
如果(0>msgrcv(msqid和接收器消息、msgsz、msgtyp、IPC\U NOWAIT))
{
perror(“msgrcv”);
/*错误处理*/
}
printf(“%s”,接收方消息.mtext);
如果(0>msgctl(msqid,IPC_RMID,NULL))
{
perror(“msgctl”);
/*根据您的要求处理错误*/
}
打破
}
您似乎在这里使用SystemV消息队列API,您可以查看POSIX消息队列API,如mq\u open
,mq\u close
,mq\u send
,mq\u receive
等。
有关消息队列概述,请参阅手册页(man mq_overview
)
使用手册页也可以获取有关API的信息。
希望这有帮助 您有几个问题:
- 您需要在调用
fork()
之前创建消息队列,以便父级和子级都可以访问它
- 消息队列的权限是从
msgget()
的第二个参数的低位设置的,因此您至少需要为消息队列的所有者指定读写权限。您可以在这里使用
中的常量S\u IRWXU
- 您正在传递
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);
intpid;
int msqid;
msqid=msgget(IPC_PRIVATE,S_IRWXU);
如果(msgid<0){
佩罗尔(“msgget”);
出口(1);
}
开关(pid=fork())//fork子进程
{//子进程
案例0:
msg.mtype=1;/*必须为正值*/
strcpy(msg.mtext,“服务于
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);