3

私の C#.Net 初心者ステータスをご容赦ください。これが明らかで、ドキュメントから見逃した場合は、関連するページまたはサンプル コードへのリンクをいただければ幸いです。

Java アプリケーションからの TCP ソケット接続を受け入れるアプリケーションに取り組んでいます。(はい、その部分には Java が必要です。これは Sun SPOT デバイスであり、Java が唯一のオプションです。) Java アプリは定期的に新しいデータをソケットに書き込みます。私のアプリの仕事は、byte[] を取り込み、変換することです。それを文字列に変換し、データを処理 (UI の更新など) し、場合によっては同様の C#.NET アプリを実行している別のコンピューターにデータを転送します。

これまでに行ったことは次のとおりです。現在、アプリは起動時にスレッドをスピンアップし、ソケットを開きます。Java アプリはソケットに正常に接続できるため、機能しています。私は NetworkStream のbeginReadメソッドと 、dataAvailablelengthおよびCanReadプロパティを見ていましたが、データの 1 つのパケット (通常は約 512 バイト) をいつ読み取ったかを確認する方法が完全にはわかりませんが、異なる場合があります。

Java アプリがデータをストリームに書き込む場合、またはデータのバックログがある場合 (Java アプリはかなり速くデータを渡します)、一度に 1 つのデータ パケットのみを読み取っていることを確認するにはどうすればよいですか? Java アプリが書き込み時にデータを null で終了する場合、それは役に立ちますか? それは十分ですか?

最後に、ソケットは 1 つの接続しか受信しませんが、エラーが発生するか接続が終了するまで開いたままにしておく必要があります。この側面を処理する最も優雅な方法は何ですか? Sun SPOT ベース ステーションで実行されている Java アプリケーションの急速な発火 (ほぼリアルタイム) の側面のため、データ パケットごとに閉じて再度開くことは機能しないと思います。現在、基地局が終了すると、私のアプリは大声で痛みを伴う死に方をします。:)

読んでくれてありがとう、そしてあなたが提供できる助けをありがとう。

4

3 に答える 3

5

「Java アプリがストリームにデータを書き込む場合、またはデータのバックログがある場合 (Java アプリはかなり速くデータを渡します。) 一度に 1 つのデータ パケットのみを読み取っていることを確認するにはどうすればよいですか?」

最終的にどのデータがどのパケットになるかを制御できると思い込まないように注意してください。バイト データを送信しようとすると{ 'H', 'e', 'l', 'l', 'o' }、このすべてのデータが 1 つのパケットで送信されるという保証はありません。可能性は非常に低いですが、各パケットに 1 バイトしか含まれない可能性があるため、5 つの異なるイベントで 5 バイトすべてを受け取ることになります。ポイントは、このようにパケットに依存しないことです。代わりに、独自の End Of Message ターミネータを定義し、すべての着信データを何らかのバイト バッファに投げ込み、これらのターミネータが存在するかどうかを検出する別の関数を用意します。もしそうなら、そのターミネータまで読んでください。たとえば、次のデータを含む Java アプリケーションからそれぞれの send メソッドを 2 回呼び出すとします。

{ 'H', 'e', 'l', 'l', 'o', '\0' }
{ 'W', 'o', 'r', 'l', 'd', '\0' }

データを受信するためにアプリケーションをどのように準備する必要があるかは、次のようになります。

Server receives { 'H', 'e', 'l' }
Data stored in byte buffer { 'H', 'e', 'l' }
Check byte buffer for message terminator '\0'. None found. Buffer unchanged, no message processed.
Server receives { 'l', 'o', '\0', 'W' }
Data stored in byte buffer { 'H', 'e', 'l', 'l', 'o', '\0', 'W' }
Check byte buffer for message terminator '\0'. 1 found, extracted message { 'H', 'e', 'l', 'l', 'o' } and buffer updated { 'W' }

それはあなたの最初の質問に対する正確な答えではありませんでしたが、正しい方向に進むべきだと思います.

遭遇する可能性があることの 1 つは、メッセージ ターミネータの代わりにデータにできない文字がないということです。たとえば、多くのファイルには \0 というデータが含まれているため、メッセージの検出がうまくいかないことがあります。これが通常どのように処理されるかは、プロトコルのヘッダー仕様を作成し、ヘッダーを期待しているかどうかを検出することです (この場合、\0 を探すことはメッセージの終わりを示します)、または特定の量のヘッダーを待っているかどうかを検出します。 data (受信した最後のヘッダーで指定できます。) これが意味をなさず、この手法を使用する必要があると思われる場合は、お知らせください。この回答に追加します。

于 2009-01-17T20:20:27.447 に答える
1

ストリーミングデータを読み取る場合、読み取りを停止して情報を処理するタイミングを決定するために、センチネル/終了文字または既知のサイズのデータ​​が必要です。ヌル文字または改行が一般的です。別の手法は、本体の長さを指定する固定サイズのヘッダーを使用することです。

ソケットは、閉じるか反対側が終了するまで開いたままになります。その場合、ハンドルをシャットダウンするソケットからの読み取り中にエラーが発生します。読み取りまたは書き込み操作中にリモート側からソケットが閉じられると、NetworkStreamはIOExceptionをスローします。

于 2009-01-17T17:43:47.420 に答える
0

これを解決した方法は、センチネル文字と固定幅フィールドを組み合わせることです。最初の 2 バイトは、パケット全体の長さヘッダーです。次に、パケットを byte[] バッファーに読み込み、独自のパケット構造に依存して、たとえば、最初の 2 バイトがそれぞれ個別のフィールドとして解釈され、文字列フィールドが \n 文字で終了することを確認します。 (ホームで得点している場合は 0x0A)。次に、長いデータ フィールドが 8 バイト連続で読み取られるなどして処理されます。これはかなりうまく機能しているように見えますが、明らかに、ソケットの両端を制御でき、一方だけが制御されている状況では解決できません。一端をコントロールできる。これが他の誰かにも役立つことを願っています。

于 2009-02-16T15:27:23.527 に答える