2

C# で書かれた単純なファイル サーバー\クライアント アプリケーションがあります。しかし、ストリームが2つの異なる読み取りを1つのバッファに書き込むという問題によく遭遇します。同期されたストリームがありますが、まだ役に立ちません。助言がありますか?ありがとう!

System.Threading.Thread.Sleep(25);
receive_fspos = new byte[30];
int bytesread = stream_1.Read(receive_fspos, 0, receive_fspos.Length);//this is where it gets combined
if (bytesread == 0) 
{ 
    finished = true; 
    System.Threading.Thread.Sleep(25); 
}
string string_1 = utf.GetString(receive_fspos).TrimEnd(new char[] { (char)0 });
int fsposition = (int)Convert.ToInt64(string_1);
bytestosend = fsposition;
filestream.Position = fsposition;
byte[] buffer_1 = new byte[bufsize];
int bytesreadfromfs = filestream.Read(buffer_1, 0, buffer_1.Length);
stream_1.Write(buffer_1, 0, buffer_1.Length);
Console.Write("\rSent " + fsposition + " / " + length + " bytes");
finished = true;
4

2 に答える 2

3

完全に理解していない場合は、独自のストリーム メソッドを作成することはお勧めしません。

あなたが抱えている問題は、着信データがバイトのストリームであり、メッセージの長さが何バイトかを知る方法がないためです。

以下のコードでは、ストリームの "receive_fspos.Length" バイトを読み取りたいと述べています。「receive_fspos.Length」が 30 であるため、読み取られるバイト数は 0 から 30 の範囲になります。

接続によって受信されたバイトが 15 バイトしかない場合。15バイトになります。メッセージの長さが 20 バイトの場合。次に、メッセージはさまざまなセグメントに分割されます。

最初のメッセージが 4 バイトで、2 番目のメッセージが 12 バイトの場合。これで、最後に 2 つのメッセージと 16 の空白バイトのセットができました。さらに悪いことに、これらの 16 の「空白」バイトは、ストリームに着信する 3 番目のメッセージの始まりになる可能性があります。

メッセージの長さが 50 バイトの場合。その後、メッセージの半分しか受信しません。ここで、読み取ったバイトを別のバッファに追加する必要があります。ストリームから再度読み取ります。次に、メッセージ全体を完了するのに必要な正確なバイト数を読み取ったと判断できるまで、これを繰り返します。次に、読み取ったすべてのバイトを 1 つのバイト [] に連結します。

     receive_fspos = new byte[30];
     int bytesread = stream_1.Read(receive_fspos, 0, receive_fspos.Length);//this is where it gets combined

独自のループを展開する代わりに、BCL メソッドを使用してください。文字列を使用しているように聞こえたので、これが推奨される方法です..次のことをお勧めします。

using(NetworkStream networkStream = tcpClient.GetStream())
using(StreamReader streamReader = new StreamReader(networkStream))
using(StreamWriter streamWriter = new StreamWriter(networkStream))
{
     networkStream.ReadTimeout = timeout; //Set a timeout to stop the stream from reading indefinately           

     //To receive a string
     string incomingString = stream.ReadLine();

     //To send a string
     stream.WriteLine(messageToSend);
     stream.Flush();
}

あなたの答えは、ファイルを送信しようとしていることを明確にしました。このために、bytes[] の配列を送信することをお勧めします。このメソッドを使用すると、シリアル化できるものなら何でも送信できます。これにはファイルが含まれます。ファイルはメモリに保存する必要があるため、ファイルのサイズには制限があることに注意してください。より大きなファイルを書き込むには、データがストリーミングされているときにデータをチャンクで保存する必要があります。

//Please note that if the file size is large enough. It may be preferred to use a stream instead of holding the entire file in memory.
byte[] fileAsBytes = File.ReadAllBytes(fileName);

using(NetworkStream networkStream = tcpClient.GetStream())
using(BinaryReader binaryReader = new BinaryReader(networkStream))
using(BinaryWriter binaryWriter = new BinaryWriter(networkStream))
{
     networkStream.ReadTimeout = timeout; //Set a timeout to stop the stream from reading indefinately           

     //To receive a byte array
     int incomingBytesLength = BinaryReader.ReadInt32(); //The header is 4 bytes that lets us know how large the incoming byte[] is.
     byte[] incomingBytes = BinaryReader.ReadBytes(incomingBytesLength);

     //To send a byte array
     BinaryWriter.Write(fileAsBytes.Length); //Send a header of 4 bytes that lets the listener know how large the incoming byte[] is.
     BinaryWriter.Write(fileAsBytes);
}
于 2013-02-23T05:46:35.580 に答える
0

動作しました。コード > 30000 文字:\ 少し面倒ですが、機能しています。

サーバー: https://www.dropbox.com/s/2wyccxpjbja10z3/Program.cs?m

クライアント: https://www.dropbox.com/s/yp78nx4ubacsz6f/Program.cs?m

于 2013-03-02T04:01:37.763 に答える