111,077
社区成员




while (m_Reader.DataAvailable || currentSize < packSize)
{
readSize = m_Reader.Read(bytes, 0, (int)m_ConnectSocket.ReceiveBufferSize);
if (readSize > 0)
{
currentSize += readSize;//读取成功,进行叠加
totalBytes = totalBytes.Concat(bytes).ToArray();//将读取的内容添加到容器后面
}
}
其中这一段是有问题的,我将数据串起来采用的是 byte.Concat方法,而该方法是将bytes添加到totalBytes后面。
bytes长度为1024。这代码在单机或网络环境好的情况是可以使用的,也是网上搜索给出的代码标准答案。
但是如果在网络没那么好的情况下,是有问题的。
Networkstream的Read方法是尽可能的往stream里面读取数据。如果网络不好的情况下,真实有用的数据可能只有512,但是Read中强行读取1024,导致bytes前512个数据是有用数据,而后面的512~1024数据则是之前的数据。
而我的代码中直接把1024的bytes添加到结果后面,这样是不正确的。
解决办法是类似下面的代码一样
if (readSize > 0)
{
LogRecord.WriteLog(readSize);
currentSize += readSize;
byte[] temp = new byte[readSize];
Array.Copy(bytes, 0, temp, 0, readSize);
totalBytes = totalBytes.Concat(temp).ToArray();//C#神器,byte[]会自动延长
}
多谢xian_wwq指出应该打印到日志内。项目中引用Log4Net将结果打到文件里面比对一下就发现问题了。
至于zanfeng指出Networkstream并不可靠,但我并不知道改用什么其他方法接收。
以及chengbin0602指出的要异步接收。
结贴给分,感谢各位!
public static ManualResetEvent allDone = new ManualResetEvent(false);
private static byte[] bytes = new byte[m_ConnectSocket.ReceiveBufferSize];
private static byte[] totalBytes = new byte[0];//C#神器,byte[]会自动延长
public class State
{
public NetworkStream ns;
public byte[] buffer;
public byte[] result;
}
public static void myReadCallBack(IAsyncResult iar)
{
State state = (State)iar.AsyncState;
NetworkStream myNetworkStream = state.ns;
int numberOfBytesRead;
numberOfBytesRead = myNetworkStream.EndRead(iar);
if (numberOfBytesRead > 0)
{
totalBytes = totalBytes.Concat(state.buffer).ToArray();
//接收到的消息长度可能大于缓冲区总大小,反复循环直到读完为止
while (myNetworkStream.DataAvailable)
{
myNetworkStream.BeginRead(state.buffer, 0, state.buffer.Length, new AsyncCallback(myReadCallBack), state);
}
}
else
{
//执行这里我认为数据已经全部接收完毕
//开始执行如11楼的处理数据代码
//也就是从 state.buffer 中取出包头判断是否我的包
//然后提取数据长度,根据数据长度提取数据,将数据交由数据处理线程进行处理
allDone.Set();
}
}
//线程接收代码如下
while (m_Reader.DataAvailable)
{
State state = new State();
state.ns = m_Reader;
state.buffer = new byte[m_ConnectSocket.ReceiveBufferSize]; ;
state.result = new byte[0];
totalBytes = new byte[0];
m_Reader.BeginRead(state.buffer, 0, state.buffer.Length, myReadCallBack, state);
allDone.WaitOne();
}
使用异步的BeginRead,但是代码没有实现我想要的结果。其实对于BeginRead很混乱,希望各位大牛能帮我理清思路。
因为网上关于BeginRead的代码真是惨不忍睹,全是代码片段,全是无脑复制,好一点的在网络环境好的情况下还能接收成功。
但更多的根本没用