C 两个分叉进程之间的消息队列导致来自msgsnd的参数无效
该程序创建两个子进程。第一个子进程(1)从stdin读取文本,删除任何特殊字符,并将其拆分为单词。程序的这一部分工作得很好。然后,当子级(1)拆分单词时,它通过消息队列发送整个单词。此部分导致无效参数错误。然后,孩子2应该将收到的信息打印回屏幕 至少我是这样计划的。我有点卡住了,不知道如何调试消息队列。现在它正在抛出一个错误C 两个分叉进程之间的消息队列导致来自msgsnd的参数无效,c,fork,posix,message-queue,C,Fork,Posix,Message Queue,该程序创建两个子进程。第一个子进程(1)从stdin读取文本,删除任何特殊字符,并将其拆分为单词。程序的这一部分工作得很好。然后,当子级(1)拆分单词时,它通过消息队列发送整个单词。此部分导致无效参数错误。然后,孩子2应该将收到的信息打印回屏幕 至少我是这样计划的。我有点卡住了,不知道如何调试消息队列。现在它正在抛出一个错误 #include <signal.h> #include <stdio.h> #include <string.h> #include
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <error.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <ctype.h>
# define QUEUE_PERMS 0644
static int message_queue = (int) 0;
static key_t key = (key_t) 0;
typedef struct message
{
long mtype;
char msg[100];
} mess_t;
int main(int argc, char *argv[]){
const char delimiters[] = " ,.-!?()1234567890@#$%^&*\n";
char *word = NULL;
size_t buffer = 100;
char *token;
mess_t message;
mess_t message2;
int i;
// set up a message queue
key = ftok(__FILE__,'x');
// create queue
message_queue = msgget(key, QUEUE_PERMS | IPC_CREAT);
if(message_queue == -1){
perror("creating message queue");
}
// create parcer process. This tokenizes the strings
// and send each work to the sort function(s)
switch(fork()){
case 0:
// child process # 1 starts here
key = ftok(__FILE__,'x');
message_queue = msgget(key, QUEUE_PERMS);
// splitting the words up here, this works fine
while(getline(&word, &buffer, stdin) != EOF){
token = strtok(word, delimiters);
while(token != NULL){
for(i = 0; token[i]; i++){
token[i] = tolower(token[i]);
}
// set type to 1 to send
message.mtype = 1;
// copy the word (token) over to the message struct
strcpy(message.msg,token);
// **** I get a send failed: Invalid argument here *****
if(msgsnd(key, &message, sizeof(message), MSG_NOERROR) == -1){
perror("send failed");
}
token = strtok(NULL, delimiters);
}
}
break;
case -1:
perror("error fork\n");
break;
default:
wait(NULL);
break;
}
// this process should read the message an print it out
switch(fork()){
case 0:
// child process # 2 starts here
key = ftok(__FILE__,'x');
message_queue = msgget(key, QUEUE_PERMS );
msgrcv(key, &message2, sizeof(message),1, MSG_NOERROR);
printf("child process got %s\n", message2.msg);
break;
case -1:
perror("error fork\n");
break;
default:
wait(NULL);
break;
}
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义队列\u PERMS 0644
静态int消息_队列=(int)0;
静态键=0;
typedef结构消息
{
长型;
char-msg[100];
}混乱;
int main(int argc,char*argv[]){
常量字符分隔符[]=“,.-!?()1234567890@$%^&*\n”;
char*word=NULL;
缓冲区大小=100;
字符*令牌;
混乱信息;
混乱信息2;
int i;
//设置消息队列
key=ftok(_文件,'x');
//创建队列
消息队列=msgget(密钥、队列管理、IPC创建);
如果(消息队列==-1){
perror(“创建消息队列”);
}
//创建parcer进程。这将标记字符串
//并将每个工作发送到排序功能
开关(fork()){
案例0:
//子进程#1从这里开始
key=ftok(_文件,'x');
消息队列=msgget(密钥、队列队列);
//在这里把单词分开,这样做很好
while(getline(&word,&buffer,stdin)!=EOF){
token=strtok(字、分隔符);
while(令牌!=NULL){
对于(i=0;令牌[i];i++){
令牌[i]=tolower(令牌[i]);
}
//将类型设置为1以发送
message.mtype=1;
//将单词(令牌)复制到消息结构
strcpy(message.msg,token);
//****我收到发送失败:此处的参数无效*****
如果(msgsnd(键和消息、sizeof(消息)、MSG_NOERROR)=-1){
perror(“发送失败”);
}
token=strtok(空,分隔符);
}
}
打破
案例1:
perror(“错误叉\n”);
打破
违约:
等待(空);
打破
}
//此过程应读取消息并将其打印出来
开关(fork()){
案例0:
//子进程2从这里开始
key=ftok(_文件,'x');
消息队列=msgget(密钥、队列队列);
msgrcv(键和消息2、消息大小、消息1、消息无错误);
printf(“子进程得到%s\n”,message2.msg);
打破
案例1:
perror(“错误叉\n”);
打破
违约:
等待(空);
打破
}
返回0;
}
您使用msgget()
设置了消息队列
消息队列ID,但随后尝试使用键而不是消息队列ID发送到msgsnd()
msgrcv()
也有同样的问题
当我修复这两个问题时,我可以运行程序:
$ ./mq
abelone apathy
child process got abelone
child process got apathy
$
我在一行中输入了abelone apathy
,然后用Control-D表示EOF
在组织好之后,在启用读取过程之前,写入过程将填充消息队列。只要输入不是太大,就行了。但是,您可能真的希望这两个进程同时运行。您需要移动wait()
调用以获得并发性。(将代码正确地划分为函数的另一个优点是,如果尽可能地隐藏,则更容易发现此类问题。)您可以使用msgget()
设置消息队列
的消息队列ID,然后尝试使用键而不是消息队列ID发送到msgsnd()
msgrcv()
也有同样的问题
当我修复这两个问题时,我可以运行程序:
$ ./mq
abelone apathy
child process got abelone
child process got apathy
$
我在一行中输入了abelone apathy
,然后用Control-D表示EOF
在组织好之后,在启用读取过程之前,写入过程将填充消息队列。只要输入不是太大,就行了。但是,您可能真的希望这两个进程同时运行。您需要移动wait()
调用以获得并发性。(将代码正确地划分为函数的另一个优点是,如果尽可能多地隐藏,则更容易发现此类问题。)(1)将错误的值设置为msgsnd/msgrcv
。在代码中使用msgget
的返回值,即message\u queue
(2) 您的fork
代码错误。父级将创建一个子级,然后点击wait
,在第一个子级死亡之前等待,然后继续创建第二个子级。您需要重新考虑在某些地方使用exit
,您只是在switch语句中使用了break
。(1)将错误的值设置为msgsnd/msgrcv
。在代码中使用msgget
的返回值,即message\u queue
(2) 您的fork
代码错误。父级将创建一个子级,然后点击wait
,在第一个子级死亡之前等待,然后继续创建第二个子级。在switch语句中仅使用了break
的某些地方,您需要重新考虑使用exit
。一个建议:使用函数封装发送方和接收方的操作。然后,您可以简化main()
函数,以便它只在正确的点调用这些函数。你的代码很好;它通过了我的编译测试(gcc-g-O3-std=c99-Wall-Wextra-Wmissing prototype-Wstrict prototype-Wold样式定义-Wold样式声明-Werror mq.c-o mq
)(