2013-02-23 81 views
2

我有一個簡單的文件服務器\客戶端應用程序香港專業教育學院用C#。但我通常遇到問題,我的流將兩個不同的讀取寫入單個緩衝區。我有一個同步流,仍然沒有幫助。有什麼建議麼?謝謝!Stream.Read是結合兩種不同的讀

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; 
+1

你是說,例如,你寫的每一個10個字節兩條消息流,並在另一端接收20個字節?這就是爲什麼它被稱爲流。一端的字節以相同的順序出來,沒有重複或丟失。沒有一個實體的概念大於一個字節,即_message_或_record_。讀取中接收的字節數取決於整個網絡的緩衝。如果您總共寫入100個字節,則可以從第一次讀取中獲得43個字節,然後從下一個字節中獲得56個字節,然後獲得單個字節。 – HABO 2013-02-23 03:56:18

+0

不完全。我已經將每個讀取的長度設置爲哦,比方說30個字節,每個消息實際上是8個字節,它在stream.read()方法的一次調用中寫入服務器的兩個stream.write()調用緩衝區。它不應該這樣做,它應該將8字節消息和22個空白字節寫入一個30字節緩衝區。對? – user2038443 2013-02-23 04:04:56

+1

對不起,但是一次讀取將檢索所有可用數據,直到緩衝區的大小。緩衝區中的任何剩餘字節都不會受到影響,即被清除。如果你想將字節流解釋爲消息,那麼_you_需要創建一種方法來確定每條消息的邊界。我已經使用了一個頭,其中前兩個或四個字節包含消息的長度。額外的頭域可能包含消息類型,子類型,ID,...。由於字節以任意大小的組接收,因此您必須準備好重新組合來自碎片的消息。即使長度字段可以分散! – HABO 2013-02-23 04:13:01

回答

3

如果您不完全瞭解它,我不會建議編寫自己的流方法。

您遇到的問題是,因爲輸入的數據是不給你知道在長度消息是多少字節的方式字節流。

在下面你的代碼,說明你想讀流的「receive_fspos.Length」字節。由於「receive_fspos.Length」是30,將被讀取的字節的量將是在任何地方從0到30。

如果只有15已經由連接接收的字節。它會給你15個字節。如果消息長度爲20個字節。然後,該消息現在分成不同的部分。

如果所述第一消息是4個字節,所述第二消息是12個字節。現在你在結尾處有2條消息和一組16個空白字節。更糟糕的是,這16個「空白」字節可能是第三條消息進入流的開始。

如果該消息是50個字節長。那麼你只會收到一半的消息。現在您需要將讀取的字節添加到單獨的緩衝區中。再次從流中讀取。然後重複此操作,直到確定您已閱讀完成整個消息所需的確切字節數。然後將所有讀取字節連接回單個字節[]。

 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(); 
} 

您的答案闡明瞭您正在嘗試發送文件。爲此我建議發送一個字節數組[]。使用這種方法,你可以發送任何可以序列化的東西。這包括一個文件。請注意,文件的大小是有限的,因爲它必須保存在內存中。爲了寫一個更大的文件,你會希望將數據保存塊,因爲它是被流

//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); 
} 
+0

在我的代碼中,我設置了它,以便從服務器讀取的字節在收到後立即寫入文件。感謝您的回答,這種方法看起來比我目前使用的方法穩定得多。我會盡快嘗試,並與你一起回去。謝謝。 – user2038443 2013-02-23 22:23:42

+0

嗯...沒有什麼似乎正在發生,我正在使用您發佈的發送和接收方法。什麼都沒有發送。 – user2038443 2013-02-24 19:13:24

+0

您是否創建了一個TcpClient和TcpListener?在使用此方法之前,請確保您有Tcp連接。 – 2013-02-24 21:29:32