より高度な言語のデータグラムパケットを覗くことは可能ですか?

私は現在、データグラム(udp)パケットを扱うCプログラムをいくつかのより高いレベルの言語に移植しようとしています。パケットは可変サイズである可能性があるので、それらのサイズを示す整数で始まります。 cでは、MSG_PEEKフラグを指定してrecvを呼び出し、最初にこの値だけを受け取ってからフィッティングバッファを割り当て、残りのパケットを読み込みます。コード(簡略化)は次のようになります。

// Simplified message format.
struct message {
    int length;
    char[] text;
}
struct message *m = malloc (sizeof(int));

// Read out in just length.
recv (sock, m, sizeof(int), MSG_WAITALL | MSG_PEEK);
int txtlen = ntohl (m->length) * sizeof(char);
int msglen = sizeof(int) + txtlen;

// Read complete packet.
m = realloc (m, msglen);
read (sock, m, msglen);
m->text[txtlen] = '\0';

// Show result.
printf("%s\n", &m->text);

私は、巨大なバッファを割り当て、より大きなパケットが到着しないことを望む、一見普通の方法を避けたい。データグラムを覗いたり、pythonやjavaなどの高水準言語で可能な限り完全な長さを事前に決定するようなことはありますか?

0
非常にリリートされたリソースを持つ組み込みシステムでない限り、間違いなく..
追加された 著者 Karoly Horvath,
UDPパケットは "巨大"ではありません(例: stackoverflow.com/questions/1098897/… )。あなたはこれについて心配するべきですか?
追加された 著者 Mat,

3 答え

巨大なバッファを割り当てようとしているように見える一般的な方法を避け、パケットがそれ以上大きくならないようにしたいと考えています。

これが何を意味するかわからないUDPパケットは一度にすべて到着するので、最初の整数はバッファの大きさを正確に示します。それが到着した後は「成長」しません。

ヌル文字を追加しているので、長さ計算でそれを考慮する必要があります:

int msglen = sizeof(int) + txtlen + 1;

realloc()を使用するときは注意してください。

m = realloc (m, msglen);

realloc が失敗すると、 m がnullに設定されます。つまり、もともと割り当てられていたメモリを唯一参照することができなくなるので、決して free()することはできません。次のようなことを試してください:

void *tmp = realloc(m, msglen)
if (tmp == null) {
 //handle the error
}
m = tmp;

And when you print the data, m->text evaluates to the address of the first character, so you can use

printf("%s\n", m->text);

あるいは、構造体を固定サイズで定義することもできます。

struct message {
  int length;
  char *text;
}

次に、 malloc()を使用して、テキストバッファを割り当てることができます:

struct message m;
recv(sock, &m.length, sizeof(int), MSG_WAITALL | MSG_PEEK);
m.text = malloc(m.length + 1);//+1 for the null that you'll append
read(sock, m.text, m.length);
m.text(m.length) = '\0';

printf("%s\n", m.text);
free(m.text);

あなたのプロジェクトに幸運を祈る - ネットワークプログラミングは常に学習体験です!

1
追加された
キャッチをありがとう!私は私の答えで訂正をしました。
追加された 著者 Adam Liss,
私はコード例でreallocをチェックするのを控え、それを簡単に保ちました。上記のように、2回の読み込み呼び出しで2つのパケットが読み込まれるため、構造体が優先されます。
追加された 著者 XZS,

UDP datagrams are limited to 64K, then ethernet frames are 1500 bytes (unless your network is using jumbo frames, which could be up to 9000 bytes). Protocol designers usually try to avoid IP fragmentation, so most likely your incoming packets are small, i.e. less then 1500 bytes.

私はちょうど1472(1500イーサネットフレーム長 - 20バイトのIPヘッダー - 8バイトのUDPヘッダー)の静的バッファから始めます。任意のプロトコルに対処する必要がある場合は、最大64Kまでバンプしてください。 MSG_PEEK で実際のサイズを収集し、便利な平均値を見つけ出し、 malloc(3) をクリックします。

0
追加された
はい、64Kは間違いなく無駄ですが、エンベデッド/リソースに制約のある環境にいない限り、この日や年齢では問題にはなりません。
追加された 著者 Nikolai Fetissov,
私は、64Kの制限は、パケットの長さを示す16ビットの長さのUDPヘッダーフィールドに続くことを期待しています。だからこれは本当に保存バッファを気にする必要があります。しかし、実際には、intを読み出すだけで、必要なメモリを事前に知ることができるということを考えると、64Kでも実際は無駄です。
追加された 著者 XZS,

なぜこれをしないのですか?

message = (struct message *)malloc(sizeof(struct message));
read(sock, &message->length, sizeof(int);
message->length = ntohl(message->length);
message->text = (char *)malloc(message->length + 1);
read(sock, message->text, message->length);
message->text[message->length] = 0;
0
追加された
残念ながら、これは2つのデータグラムを受信するので動作しません。最初の読み込みでは、たとえint以上のものが含まれていても、データグラム全体が破棄されます。
追加された 著者 XZS,