2010-12-13 12 views
3

私のCプログラムからDelphiプログラムにパケットを送信しようとしていますが、データのサイズは可変で、char data [1024];データは3バイトで、データが1024よりも大きい場合、それは文句を言わない、それがすべて内部にcharポインタを持つ構造体を送信していますか?

struct Packet 
{ 
    int State_; 
    char *Data; 
}; 

struct Packet MyPacket; 
MyPacket.Data = (char *) calloc(8, sizeof(char)); 
memcpy(MyPacket.Data, "thi sis", 8); 
send(Socket, MyPacket, (int)sizeof(struct Packet), 0); 

おかげ 窓の下でああ、ところで、イムが使用してGCCを:(送っても、それが1024のバイトを送信します

+0

**質問**は? "なぜこれは機能しないのですか?"または、他の何か? –

答えて

5

パケットを1つのブロックにカプセル化する古いトリックは、パケットの最後に長さ1の配列を使用することです。

struct Packet 
{ 
    unsigned packetLengthInBytes_; 
    /* All the fixed fields in the packet */ 
    int State_; 
    /* Generic data in the packet - of actual length given by packetDataLength(packet) */ 
    char Data[1]; 
}; 

unsigned packetDataLength(Packet* packet) 
{ 
    return packet->packetLengthInBytes_ - (sizeof(Packet) - 1); 
} 

Packet* createPacketFromData(const char* data, unsigned dataSize) 
{ 
    unsigned packetSize = sizeof(Packet) + dataSize - 1; 
    Packet* packet = (Packet*)malloc(packetSize); 
    packet->packetLengthInBytes_ = packetSize; 
    memcpy(packet->Data, data, dataSize); 
    return packet; 
} 

int sendData(int sock, const char* data, unsigned dataSize) 
{ 
    Packet* packet = createPacketFromData(data, dataSize); 
    /* [ Yes, think about endian issues.] */ 
    send(sock, packet, packet->packetLengthInBytes_, 0); 
    free(packet); 
} 

これは、我々は、単一の送信()コールを有し、一般的に1回の割当コールと一つ解放呼び出しで、単一のオブジェクトとしての周りにパケットを渡すことができることを意味どのように注意してください。

+0

ありがとう:D、かなりうまくいく、ちょうどgccのためにいくつかのmoddingが必要:D – killercode

1

受信側(Delphi)は、送信者と受信者が合意した方法でデータのサイズを認識する必要があります(つまり、データ転送のための簡単なプロトコルを実装する必要があります)。struct全体を転送する場合、あなたのプロトコルでもタイプを指定する必要があります。最も簡単な解決策は、XMLやJASONのようなテキスト形式のデータ交換フォーマットを使用することです。

// Code to demonstrate the idea, may not compile. 
struct Packet MyPacket; 
MyPacket.State_ = 0; 
MyPacket.Data = (char *) calloc(8, sizeof(char)); 
memcpy(MyPacket.Data, "thi sis", 8); 
const char* packetXml = PacketToXml(); 
/* 
packetXml = 
<Packet> 
<State>0</State> 
<Data>thi sis</Data> 
</Packet> 
*/ 
size_t len = strlen(packetXml); 
send(Socket, (char*)&len, sizeof(size_t), 0); 
send(Socket, packetXml, len, 0); 
+0

確かに、送信されたデータを盗聴しましたが、データの内容をどのように変更しても、8バイトでした。 – killercode

+0

@killercode更新された回答をご覧ください。 –

+0

私は、デルファイ側で受信したデータを手動で解析するのを避けるためにパケットを送信したいと思っていました。 – killercode

1

ポインタはメモリアドレスへの参照であり、現在コンテンツの代わりにアドレスを送信しています。したがって、実際の文字の配列を送信するように変更する必要があります。
実際の文字配列の前にサイズ情報(優先)を送信するか、文字配列の終わりを定義する必要があります

0

送信するデータの正しい長さを指定する必要があります。あなたが行っているよう

sizeof(struct Packet) 

が間違っているだけで、あなたに32ビットシステム上の8バイト、int型は4バイトで、char *のための4つのバイトを与える:使用。

char* 

が文字配列とは異なるタイプであること

注。それはcharへのポインタです。例えば、ここではsizeofの結果は異なります。

char arr[1024]; 
char* pc = arr; 
printf("%d, %d", sizeof(pc), sizeof(arr)); 
+0

私は既にsizeof(struct packet)を使っていました – killercode

+0

@killercode:上にはっきりしていないかもしれませんが、あなたが使った方法が間違っていると言及しています。 – sashang

1

あなたのコードが間違っている - あなたがそのような直接構造を送信するとき、何を送っていると、ポインタ(Data_のアドレス)ではなく、実際のです文字列。すでに述べたように

  1. 、構造の内側に固定サイズの配列を使用する:あなたは2つの選択肢があります。

  2. は手動で、たとえば、ソケットの上に実際の文字列データに続いて長さを送信します。


int length = 8; 
char *data = (char *) calloc(length, sizeof(char)); 
memcpy(data, "thi sis", 8); 
send(Socket, &length, sizeof(length), 0); 
send(Socket, data, length, 0); 
+1

また、 'int'を送信することは悪い考えです...' uint32_t'のようなtypedefを使い、異なるエンディアンに対応するために 'htonl'のような関数を呼び出すことを忘れないでください。 – asveikau

+0

いや、もっと必要な要素があれば?ユーザー状態、アカウント状態など...パケット構造体の要素の数が増えるのはどういう意味ですか? – killercode

+0

@asveikau:あなたはそれについて絶対に正しいです。 – casablanca

5

あなたはあなたの構造体の直列化メソッドを実装する必要があります。 あなたが実際にあなたのchar *の内容を送信していないので、あなたがそれを送信しようとしている方法は決してうまくいかないでしょう、あなたはポインタそのものを送ります。それは内部アドレスだけであり、受信プログラムはあなたが達成しようとしていることを全く知らないでしょう。

1

本当に、あなたのメッセージの短いヘッダーに続いて可変長データを送信してください。ヘッダーには少なくともそれに続くデータのサイズが含まれている必要があります。単純な実装は次のようになります。

struct Packet { 
    int State_; 
    char *Data; 
}; 
struct PacketHeader { 
    uint32_t state; 
    uint32_t len; 
}; 

int send_packet(int sock, struct Packet *pkt) 
{ 
    struct PacketHeader hdr; 
    int len = strlen(pkt->Data); /* If Data is a C string */ 
    hdr.state = htonl(pkt->State_); 
    hdr.len = htonl(len); 
    send(sock, &hdr, sizeof(hdr), 0); 
    send(sock, pkt->data, len, 0); 
} 

私はDelphiを知らないのですが、パケットを解析するには逆の処理を行います。ヘッダーを読んでデータのサイズを取得し、ソケットから大量のデータを新しく割り当てられたバッファに読み込みます。

関連する問題