4

ソケットが確立されたTCPサーバーとクライアントがあります。次のような場合があるとしましょう。

サーバ:

char *fn = "John";
char *ln = "Doe";

char buffer[512];

strcpy(buffer, fn);
send(*socket, buffer, strlen(buffer), 0);
strcpy(buffer, ln);
send(*socket, buffer, strlen(buffer), 0);

クライアント:

char *fn;
char *ln;

char buffer[512];

bytes = recv(*socket, buffer, sizeof(buffer), 0);
buffer[bytes] = '\0';
strcpy(fn, buffer);

bytes = recv(*socket, buffer, sizeof(buffer), 0);
buffer[bytes] = '\0';
strcpy(ln, buffer);

printf("%s", fn); 
printf("%s", ln);

期待される結果:各文字列を個別に受け取りたい(異​​なる変数に保存しているため)代わりに、最初のrecv()がfn"John"とln"Doe"の両方を連結した"JohnDoe"を取得し、プログラムがスタックします2番目のrecv()...すでに送信を行っているので。

私は次のことを試みました:-次のようにfnおよびln文字列に\0を追加します。

char *fn = "John\0";
char *ln = "Doe\0";

しかし、問題は解決しませんでした。

各文字列が別々に受信されるように課すことができる何らかの条件はありますか?

編集してさらに質問を追加します:

1)ある場合には実際に別々に送信し、他の場合には一緒に送信するのはなぜですか?

2)代わりにsend()とrecv()を使用する必要がありますか?私のコードの他のいくつかの部分では、それは自己調整であり、私がチェックする必要なしに適切なタイミングで適切な文字列を受け取るだけのようです。これでうまくいきますか?

3)送信しようとしている文字列の長さのヘッダーを送信することについて、着信文字列を解析してどこで分割するかを知るにはどうすればよいですか?どんな例でも素晴らしいでしょう。

4)バッファを指してくれてありがとう、バッファよりも大きくなっているのかどうかを確認します。

編集2:

5)私は常にサイズ512のバッファchar配列に物を入れているので、1文字の文字列を送信している場合でも、すべての送信操作でバッファのフルサイズを取るべきではありませんか?それは紛らわしいことです。私は「ジョン」を持っていますが、サイズ512の配列に入れて送信していますが、送信バッファーがいっぱいになることはありません。そのため、recv()関数は、サイズの配列全体をプルすることでネットワークバッファーを空にします。 512?

4

4 に答える 4

10

まず、クライアントがを呼び出すと、ネットワークから最大sizeof(バッファ)文字(ここでは512)recv(*socket, buffer, sizeof(buffer), 0);を受け取ります。これはネットワークバッファからのものであり、サーバーで 何回呼び出されたかとは関係ありません。または他の文字を検索しません-これはネットワークバッファからのバイナリプルです。ネットワークバッファ全体または文字のいずれかを読み取ります。sendrecv\0sizeof(buffer)

最初の名前をチェックインして、recv名前と名前の両方が含まれているかどうかを確認し、適切に処理する必要があります。

これを行うには、サーバーに文字列の長さをストリームの最初の数バイト(「ヘッダー」)として送信させるか、受信したデータをスキャンして2つの文字列があるかどうかを確認します。

呼び出すたびに本当にチェックを実行する必要がありますrecv-文字列が512バイトより長い場合はどうなりますか?recv次に、文字列を取得するために複数回呼び出す必要があります。そして、最初の文字列を取得し、2番目の文字列の半分だけを取得した場合はどうなりますか?通常、これら2つのケースは、大量のデータを処理する場合にのみ発生しますが、以前に自分のコードで発生することを確認したので、recvこのような小さな文字列を処理する場合でも、適切なチェックを組み込むことをお勧めします。早い段階で優れたコーディング戦術を実践すれば、将来的にはそれほど多くの頭痛の種はありません。

于 2012-12-01T05:39:52.877 に答える
2

正しいことは、送信されたデータをヘッダーで囲むことです。したがって、メッセージのサイズを含むメッセージのサイズを渡すと、反対側でメッセージの長さを把握できます。

ジョンは4文字なので、「0004ジョン」のような長さがあるので、いつ読むのをやめるかがわかります。ヘッダーにコマンドを追加することもできますが、これは非常に一般的です。したがって、たとえば、名は1、2番目の名前は2になります。

たとえば、「01004JOHN」はバッファに設定されて送信されます。

これを行うには、バッファにアイテムを追加してから、追加した値のサイズだけバッファ内の挿入ポイントをインクリメントします。これを使用して、バッファに多くのパーツを追加できます。*バッファのサイズを超えないように注意してください。

数値の文字列表現を渡さず、数値だけを渡さないため、これらの例は正しくないことを覚えておいてください。したがって、long int 1、long int 4、次にchars、またはいずれにしても4文字のUnicodeになります。

于 2012-12-01T05:39:41.300 に答える
2

TCPはストリーム指向であり、データグラム指向ではありません。後者の場合、あなたのものはうまくいくでしょう。次のオプションがあります。

  • SCTPを使用する
  • 信頼性を失う余裕がある場合はUDPを使用してください
  • 長さタグなどを前に付けるか、NUL各文字列を終了するためのバイトを追加することによって、操作できる方法で文字列を分離します。

後者の場合は、それでもここにあるものsend(*socket, buffer, strlen(buffer)+1, 0);を含めるだけで、送信者は2つの文字列が見つかるまで、文字列ターミネータを繰り返し検索します。NULrecv()

注意する必要があることに注意してくださいstrcpy():あなたが書いている文字列が大丈夫であると絶対に確信している場合にのみそれを使用してください。

あなたの受信機はします

bytes = recv(*socket, buffer, sizeof(buffer), 0);
buffer[bytes] = '\0';

bytes == sizeof(buffer)バッファがいっぱいの場合(より複雑な状況で発生する可能性があります)、buffer[bytes] = '\0'バッファを超えて書き込むため、これは悪いことです。SO使用

bytes = recv(*socket, buffer, sizeof(buffer) - 1, 0);

そして、あなたは幸せに行うことができます

buffer[bytes] = '\0';

于 2012-12-01T05:43:00.617 に答える
0

sizeof(buffer)の代わりにstrlen(fn);を使用します。したがって、正確なバイト数のみを送信します。nullターミネータが必要な場合は、strlen(fn)+1を使用しますが、nullターミネータをstrcat()と連結することを忘れないでください。

また、memsetでクリーニングせずにすべてのバッファサイズを送信すると、ゴミも発生するので注意してください。

于 2015-07-17T02:32:36.663 に答える