如何通过管道C 发送结构

How to send a struct over a pipe C++

本文关键字:结构 何通过 管道      更新时间:2023-10-16

我是在C 上写作的新手,并且正在努力使用管道在过程之间进行交流。我编写了一个非常简单的程序,该程序在发送字符串或整数时可以工作,但是当我尝试发送struct(在这种情况下是消息)时,我会在另一侧阅读它时会变得无效。有人对此有所了解吗?感谢您的时间。

#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不是一个琐碎的数据。那里有没有睡觉的指针。

想到这一点,将std::string写入任何东西都是血腥的。包括另一个std::string。我不会,无法使用文件。这个蓝精灵很难押韵,所以我不会再和苏斯博士一起去。

转到另一个过程,引用包含string数据的存储的指针,允许string s可以解析的魔术,可能绝对没有任何意义,如果确实意味着什么搞砸了,因为这当然不是string的数据。

即使在另一个std::string中的同一过程中,两个字符串也无法和平共存指向相同的记忆。当一个人脱离范围,调整大小或实际上会发生任何其他任何突变string不良的东西。

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

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

std::is_pod可以帮助您确定可以和读写简单的方法。

解决方案:

序列化数据。建立一个定义数据格式的通信协议,然后将该协议用作阅读和编写代码的基础。

移动string的典型解决方案就像在C的好时代一样终止缓冲区,并将string的大小预留到string中的字符,就像Pascal的好时代一样。

我喜欢Pascal方法,因为它允许您提前尺寸接收器的缓冲区。通过NULL终止,您必须播放几十轮Getta-byte,以寻找无效的终结器,并希望您的缓冲区足够大,或者通过缓冲区的动态分配和复制缓冲区的调整。

写作几乎是您现在正在做的事情,但是结构成员结构成员。在上述情况下

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

两个警告:

  1. 观看你的末日!牢固建立您的协议使用的字节顺序。如果本地Endian不匹配协议Endian,则可能需要进行一些换位才能重新定义消息。
  2. 一个人的int可能是另一个人的long的大小,因此请使用固定宽度整数。

读取更为复杂,因为单个读取的呼叫将返回最多请求的长度。获取所需的所有数据可能需要多个读取,因此您需要一个循环的函数,直到所有数据到达或无法到达,因为管道,文件,套接字和关闭的内容。

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