gpt4 book ai didi

c++ - 如何通过管道 C++ 发送结构

转载 作者:行者123 更新时间:2023-11-30 02:26:32 25 4
gpt4 key购买 nike

我对用 C++ 编写非常陌生,并且正在研究使用管道在进程之间进行通信。我写了一个非常简单的程序,当我发送字符串或整数时它可以工作,但是当我尝试发送一个结构(在这种情况下是消息)时,当我尝试在另一端读取它时,我得到 null 。有没有人对此有一些见解可以分享?感谢您的宝贵时间。

#include <unistd.h>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUFFER_LEN sizeof(message)

using namespace std;

struct message{
int from;
string msg;
};

void childCode(int *pipeOUT, int *pipeIN, message buffer){
// Local Buffer for input from pipeIN
cout << "Child: Sending Message"<< endl;

buffer.msg = "Child:I am the child!!";
write(pipeOUT[1],(char*) &buffer, BUFFER_LEN); // Test Child -> Parent comms
cout << "Child: Message Sent"<<endl;

read(pipeIN[0],(char*) &buffer,BUFFER_LEN); // Test Child <- Parent comms
cout << "Child: Recieved: "<< buffer.msg << endl;


cout << "Child Exiting..."<< endl;
exit(0); // Child process End
}


int main(int argCount, char** argVector){
pid_t pid;

int childPipeIN[2];
int childPipeOUT[2];
message buffer; // Buffer for reading from pipe

// Make Parent <- Child pipe
int ret = pipe(childPipeIN);

if (ret == -1){
perror("There was an error creating the childPipeIN. Exiting...");
exit(1);
}

// Make Parent -> Child pipe
ret = pipe(childPipeOUT);

if (ret == -1){
perror("There was an error creating the childPipeOUT. Exiting...");
exit(1);
}


// Fork off Child
pid = fork();

if (pid == -1){
perror("There has been an issue forking off the child. Exiting...");
exit(1);
}

if (pid == 0){ // Child code

cout << "Child PID = " << getpid() << endl;
childCode(childPipeIN,childPipeOUT,buffer);
}

else{ // Parent Code

cout << "Parent PID = " << getpid() << endl;

// Test Parent <- Child comms
read(childPipeIN[0], (char*) &buffer, BUFFER_LEN);

cout << "Parent: I recieved this from the child...\n" << buffer.msg << endl;

buffer.msg = "Parent: Got you message!";

// Test Parent -> Child comms
write(childPipeOUT[1], (char*) &buffer, BUFFER_LEN);

wait(null);
cout << "Parent: Children are done. Exiting..." << endl;
}

exit(0);
}

最佳答案

是的。我投票关闭。然后我更仔细地阅读了 Dupe 并意识到它没有很好地解释问题或解决方案,并且该解决方案并不真正符合 OP 的意图。

问题:

一个人不会简单地将 std::string 写入管道。 std::string 不是一个微不足道的数据。那里有不 sleep 的指针。

想想看,将 std::string 写入任何东西都是非常危险的。包括另一个 std::string。我不会,不能用文件。这个 smurf 很难押韵,所以我不会再继续讲苏斯博士了。

对于另一个进程,引用包含 string 数据的存储的指针,允许 string 调整大小的魔法,可能毫无意义,并且如果它确实意味着什么,你可以打赌它不是你想要弄乱的东西,因为它肯定不是 string 的数据。

即使在另一个 std::string 的同一进程中,这两个字符串也不能和平共存并指向同一内存。当超出范围、调整大小或执行几乎任何其他会改变 string 的操作时,就会发生错误。

不相信我?检查 BUFFER_LEN。无论您的消息有多大,BUFFER_LEN 都不会改变。

这适用于您想要写入的所有内容,而不是简单的数据 block 。整数,写掉。整数结构和固定大小的字符数组,写掉。 std::vector?没有这样的运气。您可以编写 std::vector::data 当且仅当它包含的任何内容都是微不足道的。

std::is_pod may help you decide what you can and cannot read and write the easy way.

解决方案:

Serialize the data.建立定义数据格式的通信协议(protocol),然后使用该协议(protocol)作为您读写代码的基础。

移动 string 的典型解决方案是 null 终止缓冲区,就像在 C 的美好时光一样,并将 string 的大小添加到string 就像 Pascal 的美好时光。

我喜欢 Pascal 方法,因为它允许您提前调整接收器缓冲区的大小。对于空终止,您必须玩几十轮 Getta 字节来寻找空终止符,并希望您的缓冲区足够大,或者将丑陋与缓冲区大小调整带来的动态分配和复制结合起来。

写作几乎就是您现在正在做的事情,但是逐个结构成员。在上面的例子中

  1. message.from写入管道。
  2. message.msg的长度写入管道。
  3. message.msg.data()写入管道。

两个注意事项:

  1. Watch your endian!牢固地建立协议(protocol)使用的字节顺序。如果 native 字节序与协议(protocol)字节序不匹配,则可能需要进行一些位移以重新定向消息。
  2. 一个人的 int 可能是另一个人的 long 的大小,所以使用 fixed width integers .

读取有点复杂,因为对读取的单个调用将返回最多 请求的长度。获取所需的所有数据可能需要多次读取,因此您需要一个循环函数,直到所有数据到达或由于管道、文件、套接字等关闭而无法到达。

  1. 循环读取,直到所有 message.from 都到达。
  2. 循环读取,直到到达 message.msg 的所有长度。
  3. 使用 message.msg.resize(length) 调整 message.msg 的大小以保存消息。
  4. 循环读取直到所有message.msg 都到达。您可以将消息直接读入 message.msg.data()

关于c++ - 如何通过管道 C++ 发送结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42728684/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com