2

シリアル化されたデータをLANネットワーク経由で送信しますが、情報が失われることがあります。プロセスは次のとおりです。

送信者:

  1. string mydataシリアル化されています
  2. string mydataに変換されますbyte[] bytes_of_mydata
  3. int size_of_mydataの長さですbyte[] bytes_of_mydata
  4. int size_of_mydataそれ自体がbyte[] bytes_size_of_mydata
  5. byte[] bytes_of_mydatabyte[] bytes_size_of_mydata送信されます

受信者:

  1. 私は最初に受け取りますbyte[] bytes_size_of_mydata
  2. int size_of_mydataから2番目のメッセージの長さを取得しますbyte[] bytes_size_of_mydata
  3. 私はそれから受け取りますbyte[] bytes_of_mydata、正確な長さを知っています!
  4. 次に、に変換byte[] bytes_of_mydataしますstring mydata
  5. デシリアライズstring mydata

このアプローチは通常ほとんどの状況で機能しますが、データが完全に送信されないことがあるため、文字列を逆シリアル化できません。

byte[]「レシーバー」で受信したものをデバッグしました。次のようになります。

2番目のメッセージのサイズを取得します。

int size_of_second_message = BitConverter.ToInt32(dataByteSize, 0); // 55185

バイト配列への2番目のメッセージの受信を開始します。

Byte[] dataByte = new Byte[55185];

しかし、位置5840から開始すると、0(null)を受け取り始めるため、「5840-55185」の部分はすべて「0」になります。

byte[5836] = 53;
byte[5837] = 57;
byte[5838] = 54;
byte[5839] = 49;
byte[5840] = 0; // information ends to flow
byte[5841] = 0;
byte[5842] = 0;
byte[5843] = 0;
//....
byte[55185] = 0;

上記の例は、実際のデバッガーからのものです。

だから問題は何ですか?送信中に接続が切れたようです!! なぜそれが起こっているのですか、そしてどうすればこの問題に対処できますか?それは「毎回」発生するわけではありません。

そしてここにコードが来る

送信:

//text_message - my original message
//Nw - network stream
MemoryStream Fs = new MemoryStream(ASCIIEncoding.Default.GetBytes(text_message));
Byte[] buffer = Fs.ToArray(); // total 55185 bytes (as in example)
Byte[] bufferSize = BitConverter.GetBytes(Fs.Length); // 32 bytes represent size
bufferSize = GetNewByteSize(bufferSize);

Nw.Write(bufferSize, 0, bufferSize.Length); // send size
Nw.Flush();

Nw.Write(buffer, 0, buffer.Length); // send message
Nw.Flush();

受け取る:

//get first(SIZE) bytes:
int ReadSize = 0; int maxSize = 32; // 32 - constant!
Byte[] dataByteSize = new Byte[maxSize];
int origsize;
using (var strm = new MemoryStream())
{
    ReadSize = Nw.Read(dataByteSize, 0, maxSize);
    strm.Write(dataByteSize, 0, ReadSize);
    strm.Seek(0, SeekOrigin.Begin);
    origsize = BitConverter.ToInt32(dataByteSize, 0); // origsize = 55185
}
Nw.Flush();

//get next(MESSAGE) bytes:
string message = ""; int thisRead = 0;
int max = Convert.ToInt32(origsize); // origsize = 55185
Byte[] dataByte = new Byte[max];

using (var strm = new MemoryStream())
{
    thisRead = Nw.Read(dataByte, 0, max);
    strm.Write(dataByte, 0, thisRead);
    strm.Seek(0, SeekOrigin.Begin);
    using (StreamReader reader = new StreamReader(strm))
    {
        message = reader.ReadToEnd();
    }
}
Nw.Flush();
// message - the message that is being transmitted partly (sometimes)! 

私はコードを投稿したくありませんでしたが、皆さんは通常「あなたがしたことを見せてください」と尋ねるので、ここにあります!

編集

一時的な修正は、StreamWriter、リーダーに切り替えることです。

受信+送信(サーバー):

NetworkStream Nw = new NetworkStream(handlerSocket.Client);
string toreceive = "";
StreamReader reader = new StreamReader(Nw);
toreceive = reader.ReadLine();
string text_message = "to send back";
StreamWriter writer = new StreamWriter(Nw);
writer.WriteLine(text_message);
writer.Flush();
Nw.Close();

送信+受信(クライアント):

NetworkStream Nw = new NetworkStream(handlerSocket.Client);
StreamWriter writer = new StreamWriter(Nw);
writer.WriteLine("to send");
writer.Flush();

string toreceive = new StreamReader(Nw).ReadLine();
writer.Close();
Nw.Close();

元の問題に関する解決策を探していますが、一時的な修正により、これまでのところすべてが機能しています。

4

1 に答える 1

1

TCPはストリームベースのプロトコルであり、まだ受信されていないデータを読み取ることができます。1つのステップでデータを送信するからといって、データが同じブロックで受信されるという保証はありません。予想されるすべてのデータを受信するまで、受信側でループする必要があります。

ちなみに、最初に明示的な長さフィールドがあるプロトコルは本当に良いと思います。それは単純なクライアントコードを補います(少なくともそれが得られるのと同じくらい単純です)。

しばらく前に、Xバイトのデータが使用可能になるまで待機する組み込み機能について質問しました。Xバイトが使用可能になるまで.NETブロッキングソケットの読み取りですか?。残念ながら答えはノーです。

于 2013-01-12T17:05:54.987 に答える