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

时间:2017-03-10 22:20:24

标签: c++ struct

我很擅长用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);
}

1 个答案:

答案 0 :(得分:3)

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

问题:

不只是将std::string写入管道。 std::string不是一小块数据。那里有指针不睡觉。

想到这一点,将std::string写入任何东西都是非常危险的。包括另一个std::string。我不会,也不能用文件。这种smurf难以押韵,所以我将不再与Seuss博士合作。

对于另一个进程,引用包含string数据的存储的指针,允许string s可调整大小的魔力,可能意味着什么都没有,如果它确实意味着什么,你可以打赌,这不是你想搞砸的东西,因为它肯定不是string的数据。

即使在另一个std::string的同一个进程中,两个字符串也不能和平共存,指向同一个内存。当一个人超出范围,调整大小或做其他任何会改变string不良的事情时,都会发生。

不相信我?检查BUFFER_LEN。无论您的邮件有多大,BUFFER_LEN都不会发生变化。

这适用于您想要编写的不是简单数据块的所有内容。整数,写下来。整数结构和固定大小的字符数组,写出来。 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.建立定义数据格式的通信协议,然后使用该协议作为读写代码的基础。

移动string的典型解决方案是空终止缓冲区,就像在C的好日子里一样,并将string的大小预先设置为string中的字符帕斯卡的美好时光。

我喜欢Pascal方法,因为它允许您提前调整接收器缓冲区的大小。使用null终止时,你必须播放几十个Getta字节,寻找null终止符,并希望你的缓冲区足够大,或者通过缓冲区调整大小的动态分配和复制来加重丑陋。

写作几乎就是你现在所做的,但结构成员的结构成员。在上面的例子中

  1. message.from写入管道。
  2. message.msg的长度写入管道。
  3. message.msg.data()写入管道。
  4. 两个警告:

    1. Watch your endian!牢固地建立协议使用的字节顺序。如果本机端序与协议端序不匹配,则可能需要进行一些位移以重新定向消息。
    2. 一个人的int可能与另一个人long的大小相同,因此请fixed width integers使用message.from
    3. 阅读有点复杂,因为单次调用将返回最多所请求的长度。获取所需的所有数据可能需要多次读取,因此您需要一个循环的函数,直到所有数据到达或无法到达,因为管道,文件,套接字等都已关闭。

      1. 循环读取,直到message.msg全部到达。
      2. 循环读取,直到message.msg.resize(length)的所有长度都到达。
      3. 使用message.msg调整message.msg的大小来保留邮件。
      4. 循环读取,直到所有message.msg.data()都到达。您可以直接将消息阅读{{1}}。