0

私は C++ ソケットの割り当てに取り組んでおり、サーバーからクライアントに文字列を送信しようとしています。

const char* msg;
msg = "test";

クライアントtestがコンソールに出力しますが、次のことを試してみると:

std::string msg;
std::getline(std::cin, msg);

印刷された結果は意味不明です。送信する前に、メッセージを保持する構造体をシリアル化し、メッセージはそのままです。逆シリアル化されたパッケージを確認すると、メッセージがめちゃくちゃです。

次の構造体を使用しています。

struct Package{
unsigned int package_type;
const char* msg;
int senderid;
int receiveid;

void SerializeData(char* _data){
    memcpy(_data, this, sizeof(Package));
}

void DeserializeData(char* _data){
    memcpy(this, _data, sizeof(Package));
}
};

コードで定義された const char* が機能するのに、string.c_str() が機能しない理由がわかりませんか?

4

2 に答える 2

2

SerializeData関数と関数は実際には文字列をシリアライズ/デシリアライズしませDeserializeDataん。へのポインタをシリアライズ/デシリアライズしますがchar、これはまったく異なります。それは単なるポインタです!

各プロセスには独自のプライベートアドレス空間があるため、ネットワークを介して異なるプロセス間で実際のポインターを渡すことはほとんど意味がありません。

あなたの例は、実行可能ファイル自体に割り当てられたコンパイル時定数である"test"ため、おそらく機能します。"test"同じ実行可能ファイルが送信者と受信者として機能する場合、定数文字列が両方で同じ場所にあることは完全に妥当です。(ただし、保証はされません。Address Space Layout Randomization などの OS ハードニング機能はそれを破ります。)string.c_str()対照的に、によって提供されるポインターは非常に一時的なものであり、実行時に動的に生成されます。

実際に文字列をパケットにシリアル化する必要があります。これには、長さフィールドをどこかに追加するか、可変サイズのメッセージを処理するための他の手段が必要になる可能性があります。

あなたの課題が文字列を一方の端からもう一方の端に送信することだけである場合、この問題をかなり単純化できる可能性があります。任意のメッセージを完全にシリアル化する必要がある場合は、さらに複雑になります。メッセージに関するある種の文法、または送信者と受信者の間で共有されるメッセージ形式のある種の期待のいずれかが必要です。

いずれにせよ、ポインターまたは参照を使用して構造体をシリアル化するときは、ポインターまたは参照を直接ではなく、ポイント先または参照先のオブジェクトを確実に取り込む必要があります。完全に一般的なシリアル化は簡単ではありません。@Sorin がページの他の場所で示したように、Google Protocol Buffers はこれを行う 1 つの方法です。

于 2013-11-13T13:25:02.927 に答える
1

シリアル化されたパッケージには0 0xabc 0 0、 0xabc が文字列が格納されているメモリ内のポインターであるようなものが含まれています。反対側では一致しません。

シリアル化されたパッケージを 16 進エディタなどでダンプし、意味があるかどうかを確認します。おそらく、各要素を 1 つずつシリアル化し、実際の文字列をシリアル化されたパッケージにコピーする必要があります。

これは難しいです。ライブラリを使用してシリアル化を行います。これはhttps://code.google.com/p/protobuf/の 1 つですが、他にもあります。

于 2013-11-13T13:23:30.913 に答える