我发送文件名(字符串),filesize(int)和文件(byte [])。发生的事情是,在某些情况下,取决于在服务器端处理数据的速度,NetworkStream已经读取了我不需要的数据。
示例:我执行.Read获取文件名,我将获取filename,filesize和文件原始数据的数据。我假设发生这种情况是因为服务器只是执行.Write并在第一个.Read尚未执行时将数据写入流。这最终会破坏我的文件大小。阅读。现在,当我为我的文件大小做一个.Read时,我显示了一个巨大的数字,当我去读取文件本身并根据读取文件大小分配一个新的byte []时,我得到一个OutOfMemory异常。
如何正确同步Read?我在网上找到的例子就像我一样。
一些代码:
private void ReadandSaveFileFromServer(TcpClient clientATF, NetworkStream currentStream, string locationToSave)
{
int fileSize = 0;
string fileName = "";
int readPos = 0;
int bytesRead = -1;
fileName = ReadStringFromServer(clientATF, currentStream);
fileSize = ReadIntFromServer(clientATF, currentStream);
byte[] fileSent = new byte[fileSize];
while (bytesRead != 0)
{
if (currentStream.CanRead && clientATF.Connected)
{
bytesRead = currentStream.Read(fileSent, readPos, fileSent.Length);
readPos += bytesRead;
if (readPos == bytesRead)
{
break;
}
}
else
{
WriteToConsole("Log Transfer Failed");
break;
}
}
WriteToConsole("Log Recieved");
File.WriteAllBytes(locationToSave + "\\" + fileName, fileSent);
}
private string ReadStringFromServer(TcpClient clientATF, NetworkStream currentStream)
{
int i = -1;
string builtString = "";
byte[] stringFromClient = new byte[256];
if (clientATF.Connected && currentStream.CanRead)
{
i = currentStream.Read(stringFromClient, 0, stringFromClient.Length);
builtString = System.Text.Encoding.ASCII.GetString(stringFromClient, 0, i);
}
else
{
return "Connection Error";
}
return builtString;
}
private int ReadIntFromServer(TcpClient clientATF, NetworkStream currentStream)
{
int i = -1 ;
int builtInteger = 0;
byte[] integerFromClient = new byte[256];
int offset = 0;
if (clientATF.Connected && currentStream.CanRead)
{
i = currentStream.Read(integerFromClient, offset, integerFromClient.Length);
builtInteger = BitConverter.ToInt32(integerFromClient, 0);
}
else
{
return -1;
}
return builtInteger;
}
我尝试过使用偏移......没有任何问题。非常感谢您的帮助。
我开始了另一个问题,但它与其他问题有关。
提前致谢 肖恩
编辑:这是我的发送字符串代码:
private void SendToClient( TcpClient clientATF, NetworkStream currentStream, string messageToSend)
{
byte[] messageAsByteArray = new byte[256];
messageAsByteArray = Encoding.ASCII.GetBytes(messageToSend);
if (clientATF.Connected && currentStream.CanWrite)
{
//send the string to the client
currentStream.Write(messageAsByteArray, 0, messageAsByteArray.Length);
}
}
答案 0 :(得分:1)
TCP / IP是流式传输,而不是数据报,所以你想要的行为就不存在了。您可以通过让流包含足够的信息进行解析来解决它。
换句话说,您可以在一行文本之后使用分隔符,例如CR / LF,或者您可以给出即将到来的数据的长度。您也可以在适当的地方使用固定大小的字段。
答案 1 :(得分:1)
你不能依赖于一次从流中读取多少字节,你的ReadStringFromServer
方法中存在一个错误,假设字符串是固定长度(256)。
而不是:
i = currentStream.Read(stringFromClient, 0, stringFromClient.Length);
builtString = System.Text.Encoding.ASCII.GetString(stringFromClient, 0, i);
尝试:
do
{
i = currentStream.Read(stringFromClient, 0, 256 - builtString.Length);
builtString+=(System.Text.Encoding.ASCII.GetString(stringFromClient, 0, i));
} while(builtString.Length < 256)
答案 2 :(得分:1)
更好的解决方案可能是将所有数据序列化(例如JSON)并通过网络流传递所有数据。
答案 3 :(得分:1)
Read()你调用它的方式将拉出256个字节;这就是stringFromClient.Length设置的原因。
您有两种方法可以准确地切断数据流,这两种方法都涉及了解或创建某种方法来确定数据之间的边界。它们是分隔流和固定长度的流。
对于分隔格式,您选择一个不会用作文件名或大小的有效部分的字符(管道,空格,制表符,换行符等),并在文件名和大小之间插入一个字符,以及大小和文件内容之间。然后,一次读取一个字节到数组,直到你达到分隔符。到目前为止您读取的字节除了分隔符是您的数据;提取成可用的形式并返回。这通常会使流更短,但需要一个可能的角色永远不会被使用。
对于固定大小的格式,确定数据的任何合理值不会超过的字节数。例如,文件名不能超过256个字符(更可能不超过50个;一些较旧/较简单的操作系统仍然限制为8个)。在任何Windows环境中,文件大小不能超过2 ^ 64字节,并且该数字可以用4个字节的原始数字数据或20个字符的字符串表示。因此,无论您选择何种限制,请使用适当的缓冲区填充数据;对于原始数字,强制转换为Int64并将其切换为字节,而对于字符串,则填充空格。然后,你知道第一个X字节恰好是文件名,接下来的Y字节恰好是文件大小,之后的任何内容都是内容。这会使流更大,但内容可以是任何内容,因为没有特殊或保留的字节值。