我正在尝试编写一个程序来实现父进程和子进程之间的基本消息传递。我以前从未使用过 C,所以过去 2 天我一直在跌跌撞撞地阅读教程,但我似乎无法让它工作。我最多能做的就是创建没有错误的消息队列。这是我的代码,以我对我正在做的事情的最佳理解进行评论:
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
//this is the structure of the message i'm sending to the queue
struct message
{
long messagetype;
char text[10];
};
int main()
{
key_t key = 2222;
int msqid = msgget(key, IPC_CREAT); //create a message queue with the key
pid_t parentpid = getpid();
pid_t childpid = fork(); //these are mostly unused for now
if(childpid < 0) //fork failed
{
printf("fork failed\n");
return 1;
} else if(childpid == 0) //in child process
{
struct message sndmsg; //create a message to be send to the queue
printf("input message\n");
scanf("%s", sndmsg.text); //get the messages text fro input
printf("Sending message to queue: %s\n", sndmsg.text);
sndmsg.messagetype = 1; //set message type to 1
if(msgsnd(msqid, &sndmsg, sizeof(sndmsg.text), 0) < 0 ) // no idea what the last parameter really means here. check if message send fails
{
printf("error sending message\n");
} else
{
printf("sent message with text: %s\n",sndmsg.text);
}
printf("child process\n");
} else
{
wait(NULL); //wait until child process is done
struct message rcvmsg; //create a message to recieve the test from the queue
rcvmsg.messagetype = 1; //matching the message type here
if(msgrcv(msqid, &rcvmsg, sizeof(rcvmsg.text), 1, 0) < 0) //again, no idea what the last parameter does here. Checking to see if message recieve fails.
{
printf("error recieving message\n");
} else
{
printf("recieved message text : %s\n", rcvmsg.text);
}
printf("Parent process\n");
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我运行时,消息发送和接收都失败。我完全不知道 IPC_CREATE、IPC_NOWAIT 等的含义。一般来说,最后一个参数在 msgsnd 和 msgrcv 中的作用是什么。在示例中,我看到人们使用 0660 | IPC_CREAT,没有解释 0660 是什么。任何人都可以阐明我在代码中做错了什么,或者为通常使用 C# 和 Java 的人解释一下 C 中的消息传递,因为现在它基本上是黑魔法。到目前为止,我发现的每一个资源或教程一旦达到某一点就会超出我的想象。谢谢。
您不会在纯标准 C 中实现 进程间通信,因为 C11 标准(读取n1570)不了解它们,并且因为任何 IPC 设施都是特定于操作系统的(特别是 Windows 上的 IPC 设施与 Windows 上的 IPC 设施非常不同) Linux)。
然而,一些操作系统提供进程间通信设施。然后您可以使用它们(无需实现它们),当然是以某种操作系统特定的方式。
在 Linux 上,更喜欢使用 POSIX 消息工具(而不是svipc(7)中记录的旧 SystemV IPC ),请参阅mq_overview(7)。还要注意pipeline(7)、fifo(7)、socket(7)、unix(7)、signal(7)、shm_overview(7)、sem_overview(7)(因为有很多方法可以进行进程间通信) 。
我完全不明白 IPC_CREATE 的含义
您需要先阅读svipc(7),它说:
IPC_CREAT如果键不存在则创建条目。
然后你问:
任何人都可以阐明我在代码中做错了什么吗
您忘记测试失败(另请参阅errno(3) & perror(3) & strerror(3))。您正在使用的每个函数都有文档记录(您应该阅读该文档)并且可能会失败(并且您需要以某种方式处理失败情况)。首先读取msgget(2),然后通过添加适当的检查进行编码,因此至少:
int msqid = msgget(key, IPC_CREAT);
if (msgid<0) { perror("msgget"); exit(EXIT_FAILURE); }
Run Code Online (Sandbox Code Playgroud)
对于您使用的所有其他系统功能也是如此。
不要忘记仔细阅读您使用的每个功能的页面man。另请参见man(1)。
收到错误消息后,您将能够再次参考文档并改进代码。
您可以使用strace(1)(它给出syscalls(2)中列出的每个系统调用- 由某个进程或命令完成)来了解正在发生的情况。
您需要花费几天或几周的时间阅读更多有关 C 编程和 Unix 系统编程的内容(例如阅读旧的ALP或更新的内容)。您还应该阅读一些有关操作系统的内容,例如操作系统:三个简单的部分(可免费下载)。
什么
0660是
可能与文件访问和权限有关(八进制0660可能对应于rw-rw----)。另请参见凭证(7)、chmod(2)、stat(2)、inode(7)。
附言。在更改一行代码之前,您确实需要花几天或几周的时间进行阅读,一旦您了解更多如何对 Linux 系统进行编程,您最好从头开始。
还可以从与您的关注点和兴趣相关的现有 自由软件项目(例如在github上)中寻找灵感。