2017-03-10 10 views
0

私はC++で書くのがとても新しく、パイプを使ってプロセス間の通信を行っています。私は文字列や整数を送信しているときに動作する非常に単純なプログラムを書いていますが、構造体(この場合はメッセージ)を送信しようとすると、反対側でそれを読み取ろうとするとnullになります。誰もが共有することについていくつかの洞察を持っていますか?御時間ありがとうございます。パイプを介して構造体を送る方法C++

#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); 
} 
+3

ソケットの上に裸の構造を投げ込むことはできません。それらを適切に*シリアル化する必要があります。 'std :: string'はあなたのプロセスに固有のポインタデータを持ち、他のプロセスにとってまったく無意味です。 – tadman

答えて

2

ええ。私は閉会することにしました。その後、私はDupeをより詳細に読んで、それが問題または解決策を非常にうまく説明しなかったことを認識し、解決策はOPの意図に実際には合致しませんでした。

問題:

一つは、単にパイプにstd::stringを書き込みません。 std::stringは簡単なデータではありません。そこには眠らない指針があります。

何かにstd::stringを書くのは危険だ。別のstd::stringを含む。私は、ファイルではできませんでした。このスマーフは韻を踏むのが難しいので、私はスース博士とはもう話しません。別のプロセスに

stringのデータを含むストレージ、string sがサイズ変更可能にすることができます魔法を参照するポインタは、おそらく絶対に何も意味しない、それが何かを意味しているのならば、あなたはそれが何かあなたではありません賭けることができますそれは確かにstringのデータではないので、混乱したい。

同じプロセスであっても、もう1つのstd::stringでは、2つの文字列が同じメモリを指すように平和的に共存することはできません。スコープが外れたり、サイズが変更されたり、実際に何か他のものが変異すると、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の大きさを付加nullです。

私は、受信機のバッファを事前にサイズ設定することができるので、私はパスカルのアプローチが好きです。ヌルターミネーションでは、ヌルターミネータを探して数十ラウンドのGettaバイトを再生し、バッファのサイズが十分に大きいか、またはバッファのサイズ変更に伴う動的な割り当てとコピーで醜さが混乱しないようにしなければなりません。

今はあなたが今やっていることはかなり書いてありますが、構造体メンバは構造体メンバです。上記の場合

  1. パイプにはmessage.fromを書きます。
  2. パイプへの書き込み長はmessage.msgです。
  3. パイプにmessage.msg.data()を書きます。

つの注意点:

  1. Watch your endian!はしっかりとあなたのプロトコルで使用されるバイト順序を確立します。ネイティブエンディアンがプロトコルエンディアンと一致しない場合、メッセージの向きを変更するためにビットシフトが必要な場合があります。
  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()にメッセージを読むことができます。
+0

単にstd :: stringをMordorに送るのではありません。 – Yakk

+0

ああ、あなたは "シリアライズ"のようなキーワードを言及したいかもしれません – Yakk

+0

クラップス。私は持っていると思った。 – user4581301

関連する問題