7

あなたと私がTCPを介して非常に長い文(たとえば、1024000バイト)を送信していると想像してください。

私に1024000バイトの文を書く場合、実際にはNetworkStreamを使用してそれらのバイトをに書き込みます。

受け取ったら、送った文章の大きさを事前に知っておく必要がありますか?

そうでない場合、stream.readをいつ停止する必要があるかを確認するにはどうすればよいですか?

はいの場合、プログラムには、データの先頭にデータサイズを埋め込む機能が必要ですか?それで、最初に4バイトを受け取って、合計でいくつ読み取る必要があるかを確認しますか?

.Netには、転送にデータサイズを自動的に埋め込むものがありますか?

4

9 に答える 9

4

.NET にも TCP プロトコルにも、メッセージのサイズを事前に定義するための組み込み機能はありません。TCP プロトコルは、すべてのデータが受信側のエンドポイントに転送されること (または、少なくともそのために最善の努力が払われること) のみを指定します。

読み取るデータの量を受信者に知らせる方法を定義する責任は、すべてあなたにあります。これを行う方法の詳細は、他の人が指摘したように、転送するものの性質に依存します。前述のように最初に長さを送信し、ターミネーターと呼ばれる特別なシーケンスをエンコードし、事前定義されたデータチャンクを使用できますしたがって、すべてのメッセージは同じサイズになります。

編集

これはコメントとして始まりましたが、その制限に適合する以上のものがあります。

ストリームに NULLを追加することは、バイナリ値 0 を持つ文字を追加することを意味します (文字 と混同しないでください0)。転送に使用しているエンコーディング (ASCII、UTF-8、UTF-16 など) によっては、1 つまたは複数の 0 バイトの送信に変換される場合がありますが、適切な変換を使用している場合は\0、あなたの文字列。次に例を示します。

string textToSend = "This is a NULL Terminated text\0";
byte[] bufferToSend = Encoding.UTF8Encoding.GetBytes(textToSend);

もちろん、上記のすべては、送信している残りのすべてのデータに他の NULL が含まれていないことを前提としています。これは、テキストであり、任意のバイナリ データ (ファイルの内容など) ではないことを意味します。それはとても重要です!そうしないと、NULL をメッセージ ターミネータとして使用できず、別のスキームを考え出す必要があります。

于 2010-02-16T14:49:59.093 に答える
1

重要な点は、TCPでは、送信側のソケット書き込みの数とサイズと、受信側のソケット読み取りの数/サイズとの間に対応関係がないことです。

データのストリームに何らかの構造がある場合は、ペイロードの周囲にある種のメタ/ラッパーデータを追加する必要があります。

この問題を解決しなければならないときはいつでも、次の組み合わせを使用しました。

a)マジックナンバーを使用して、データメッセージの開始または終了(あるいはその両方)を示します

b)メッセージの最後にチェックサムを使用して内容が正しいことを確認します(TCPがエラーチェックと再送信を実行することは知っていますが、受信者が開始/終了マジックナンバーの偶発的な発生を検出した場合にチェックサムは便利です/ストリーム内のシーケンス)

c)最初のマジックナンバーの後に長さフィールドを使用します(送信側が送信開始前にデータの長さを知っている場合)

ただし、DIYに進む前に、使用している言語/プラットフォーム用に実装されている高レベルのプロトコルライブラリをよく確認してください。NetworkStream?そのWindowsAPI/MFCか何かです。

たとえば、最近、クライアント/サーバーシステムをセットアップする必要がありました。クライアントとサーバーの機能はすでにPythonで記述されているため、python xmlrpclib / serverを使用するだけで、2つのプログラムを完全に簡単に結合できます。文字通り例をコピーして30分で完了しました。自分で作り上げたプロトコルをtcpで直接コーディングしたとしたら、5日でした。

于 2010-02-16T15:00:27.870 に答える
0

TCPなどの任意のストリームにラップできるBinaryReader/BinaryWriterクラスを調査することもできます。

これらは、他の機能の中でも、文字列の長さも含めるように注意しながら、(選択したエンコーディングで)文字列の読み取り/書き込みをサポートします。

于 2010-02-16T17:51:29.700 に答える
0

私の答えはノーでしょう。特に大規模なデータセットの場合。その理由は、最初にサイズを送信すると、システムに遅延が追加されるためです。

最初にサイズを送信する場合は、送信を開始する前に回答全体を計算する必要があります。

一方、終了マーカーを使用すると、次のデータを計算しながら、準備ができたらすぐにデータの最初のビットの送信を開始できます。

于 2010-02-16T15:01:29.037 に答える
0

TCP は信頼できるプロトコルであるため、受信バイト数を示すようにプロトコルを構成するか、何らかのターミネータを使用して送信の終了を示すことができます。信頼性が保証されていない UDP を使用している場合は、ドロップされたバイトに耐えるプロトコルを構築するか、終端を含むパケットが送信されてから予想されるバイト数を示す (および再送信メカニズムを備えている) プロトコルを構築することがはるかに重要です。失われる可能性があります。最大データ転送時間とタイムアウトも役立つ場合がありますが、妥当な最大値を決定できる場合に限ります。

于 2010-02-16T14:48:44.513 に答える