关于NetworkStream.Read方法

zanpen2001 2012-09-27 12:54:52

NetworkStream的发送接收问题。

发送端代码:

internal bool SendByteArray(byte[] buffer, NetworkStream stream)
{
if (buffer.Length == 0) return false;
try
{
WriteSize(stream, buffer.Length);
stream.Write(buffer, 0, buffer.Length);
stream.Flush();
return true;
}
catch (Exception)
{
return false;
}
}


如下的接收端代码没有问题:

internal byte[] ReceiveByteArray(NetworkStream stream)
{


int bufferlen = GetSize(stream);
byte[] resultbyte = new byte[bufferlen];

for (int i = 0; i < bufferlen; i++)
{
resultbyte.SetValue((byte)stream.ReadByte(), i);//每次顺序读取一个字节
}
return resultbyte;
}


但改成如下形式就不行了:

internal byte[] ReceiveByteArray(NetworkStream stream)
{
int bufferlen = GetSize(stream);
byte[] resultbyte = new byte[bufferlen];
stream.Read(resultbyte, 0, resultbyte.Length);
return resultbyte;
}



或者改成下面这样,还是不行:


internal byte[] ReceiveByteArray(NetworkStream stream)
{
try
{
int bufferlen = GetSize(stream);
byte[] resultbyte = new byte[bufferlen];
stream.Read(resultbyte, 0, resultbyte.Length);
return resultbyte;

byte[] data = new byte[1024];


int index = 0, bytesread = 0;
//int r = data.Length;
while (index < bufferlen && (bytesread = stream.Read(data, 0, data.Length)) > 0)
{
//r = bufferlen - index >= 1024 ? 1024 : bufferlen - index;
data.CopyTo(resultbyte, index);
index += bytesread;
}

return resultbyte;
}
catch (Exception)
{
throw;
}


上面代码段中,WriteSize()和GetSize()分别是向stream中写入和读取流中数据大小信息的方法。

现在的问题是,不想用ReadByte()方法, 但是用Read()方法,想了很多办法都不行,其中有粘包问题,数组超界问题,各种问题,确定发送端没有使用多线程。

请高手帮忙看下是怎么回事,这段接收的代码该怎么写?

...全文
589 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
zanpen2001 2012-10-08
  • 打赏
  • 举报
回复
非常感谢各位,尤其是热心的 qldsrx, 结贴给分。
__天涯寻梦 2012-09-28
  • 打赏
  • 举报
回复
加一个方法 ReadBuffer
static byte[] ReadBuffer(NetworkStream stream, int length)
{
byte[] buffer = new byte[length];
int index = 0;
do
{
int len = stream.Read(buffer, index, length - index);
index += len;
} while (index < length);
return buffer;
}

private int GetSize(NetworkStream stream)
{
int count = 0;
try
{
count = BitConverter.ToInt32(ReadBuffer(stream, _messageLength), 0);
}
catch (Exception ex)
{
Logger.ExceptionLog(ex, "");
}
return count;
}

internal byte[] ReceiveByteArray(NetworkStream stream)
{
int len = GetSize(stream);
return ReadBuffer(stream, len);
}
qldsrx 2012-09-28
  • 打赏
  • 举报
回复
[Quote=引用楼主 的回复:]
上面代码段中,WriteSize()和GetSize()分别是向stream中写入和读取流中数据大小信息的方法。
[/Quote]
你直接说你定义了消息头不就得了?让我误解了好久。
下面是完整的代码,另外#11楼估计也可以,但是用到了不推荐的GOTO语句,代码逻辑较乱。
        internal byte[] ReceiveByteArray(NetworkStream stream)
{
try
{
int bufferlen = GetSize(stream);
byte[] resultbyte = new byte[bufferlen];

int offset = 0, bytesread = 0;
while (offset < bufferlen)
{
bytesread = stream.Read(resultbyte, offset, bufferlen - offset);
if (bytesread == 0)
throw new Exception("网络异常断开,数据读取不完整。");
else
offset += bytesread;
}
return resultbyte;
}
catch (Exception)
{
throw;
}
}

qldsrx 2012-09-28
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 的回复:]

C# code

internal byte[] ReceiveByteArray(NetworkStream stream)
{
int bufferlen = GetSize(stream);
byte[] resultbyte = new byte[bufferlen];
int recieveLength = 0;……
[/Quote]
头像笑个屁啊,错误代码贴出来还笑。
wenbin 2012-09-28
  • 打赏
  • 举报
回复

internal byte[] ReceiveByteArray(NetworkStream stream)
{
int bufferlen = GetSize(stream);
byte[] resultbyte = new byte[bufferlen];
int recieveLength = 0;
READ:
int rec = stream.Read(resultbyte, recieveLength, bufferLen - receiveLength);
if(rec == 0) {
//网络断了,关闭
stream.Close();
return null;
}
recieveLength += rec;
if(recieveLength < bufferLen) {
goto READ;
}

return resultbyte;
}
qldsrx 2012-09-28
  • 打赏
  • 举报
回复
别可是不可是的,原理都解释了你还不懂,那还不如直接调试,实践出真理,你把ReceiveByteArray里面的第一句
int bufferlen = GetSize(stream);
byte[] resultbyte = new byte[bufferlen];
都删除了,直接返回data 和 bytesread ,
因为无法同时返回2个,那么你可以用out参数,例如
internal byte[] ReceiveByteArray(NetworkStream stream,out int bytesread )
{

....
return data;
}
不过这么简单的几行代码,不封装直接调用更加快速方便稳定可靠。你封装了反而出错,因为你只返回了一个data,并未返回它所加载的数据长度,不是1024字节都是可用的,只有bytesread的长度可用。
zanpen2001 2012-09-28
  • 打赏
  • 举报
回复
to qldsrx:

可是我只读取了指定的字节数啊,那里存放的是WriteSize()写入的该Stream的长度。
qldsrx 2012-09-27
  • 打赏
  • 举报
回复
就是你那个GetSize方法害人,把那个方法删除,别用,在你的GetSize方法中,你已经调用了一次stream.Read,这个方法是不能随便调用的,每次调用,就会把读取到的东西从stream里面清除,你说你还能读到正确的数据吗?
zanpen2001 2012-09-27
  • 打赏
  • 举报
回复

internal byte[] ReceiveByteArray(NetworkStream stream)
{
try
{
int bufferlen = GetSize(stream);
byte[] resultbyte = new byte[bufferlen];
byte[] data = new byte[1024];

int index = 0, bytesread = 0;
while (index < bufferlen && (bytesread = stream.Read(data, 0, data.Length)) != 0)
{
data.CopyTo(resultbyte, index);
index += bytesread;
}
return resultbyte;
}
catch (Exception)
{
throw;

}
}


求高人帮我修改一下
zanpen2001 2012-09-27
  • 打赏
  • 举报
回复
我还是贴出WriteSize()和GetSize()两个方法来吧


private void WriteSize(NetworkStream stream, int size)
{
byte[] length = new byte[_messageLength];
BitConverter.GetBytes(size).CopyTo(length, 0);
stream.Write(length, 0, _messageLength);
}



private int GetSize(NetworkStream stream)
{
int count = 0;
byte[] countBytes = new byte[_messageLength];
try
{
if (stream.Read(countBytes, 0, _messageLength) == _messageLength)
{
count = BitConverter.ToInt32(countBytes, 0);
}
else
{
return 0;
}
}
catch (Exception ex)
{
Logger.ExceptionLog(ex, "");
}
return count;
}


lshfong 2012-09-27
  • 打赏
  • 举报
回复
你先取到stream.Read的返回值
qldsrx 2012-09-27
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]

C# code
byte[] allstreambyte = new byte[GetSize(stream)];
byte[] buffer=new byte[1024];
int num=0;
while(readstream.Read(buffer, 0, buffer.Length)>0)
……
[/Quote]
网络流不支持获取流长度,所以你想要事先得到流的长度是不可能的。
victo7 2012-09-27
  • 打赏
  • 举报
回复
byte[] allstreambyte = new byte[GetSize(stream)]; 
byte[] buffer=new byte[1024];
int num=0;
while(readstream.Read(buffer, 0, buffer.Length)>0)
{
for (int i = 0; i < buffer.Length; i++)
{
allstreambyte[num * buffer.Length + i] = buffer[i];
}
num++;
}


按照你上面的逻辑,参考上面的代码。
很奇怪的代码
qldsrx 2012-09-27
  • 打赏
  • 举报
回复
是你写错了,必须捕获那个stream.Read的返回值,那个才是实际读取的字节数,不能用bufferlen,否则就会出错。
victo7 2012-09-27
  • 打赏
  • 举报
回复
ReadByte是按照Byte去读
Read是按照指定的byte长度去读
仅此区别而已

110,893

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧