2013-02-23 71 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