当前位置: 代码迷 >> C# >> NetworkStream 异步读取出现错误
  详细解决方案

NetworkStream 异步读取出现错误

热度:115   发布时间:2016-05-05 04:17:15.0
NetworkStream 异步读取出现异常
VS2013(管理员) W8.1

SOCKET 使用了异步方式,在读取客户机发来的信息时,出现异常,"尝试读取损坏的内存"
不明白啊.这是为什么,怎么解决

// 读取客户端发来的消息
private static void ReceiveData(TcpClient client)
        {
            // 获得网络流
            NetworkStream ns = client.GetStream();
            // 是否可读
            if (ns.CanRead)
            {
                // 数据缓冲区
                byte[] buffer = new byte[1024];
                StringBuilder sb = new StringBuilder();
                //接收到的消息长度可能大于缓冲区总大小,反复循环直到读完为止
                while (ns.DataAvailable)
                {
                    ns.BeginRead(buffer, 0, buffer.Length, ReceiveCallBack, ns);// 异常在这里,最后一个参数,说是读取损坏的内存.这是在调试时异常的,但是我再按F5它就过去了,而且消息也读出来了.
                    sb.Append(Encoding.UTF8.GetString(buffer));
                }
                GlobalVar.FromClientMsg = sb.ToString();
            }
            else
            {
                // 读取失败
            }
        }

------解决思路----------------------
你写的这类代码,就只能使用 Read 而不能使用  BeginRead。

真正异步操作根本不写如此复杂的 while 循环的。否则你就不应该使用  BeginRead。

另外你也不应该在一次 ns.Read 之后就执行 Encoding.GetString(...)。你应该在确定收到包结束区域之后,并且保证不沾包的情况下,才对字符串解码。

我在另一个帖子写了一个例子:http://bbs.csdn.net/topics/390987992
------解决思路----------------------
既然用 BeginRead, 那下一句怎么能马上就取buffer, 这里应该还没有读取吧.
虽然代码不多,但感觉很混乱,
------解决思路----------------------
就代码而言,你显然遗漏了什么。因为
每次调用 BeginRead 时都必须调用 EndRead。无法结束一个读取进程就开始另一个读取可能导致死锁等不希望出现的行为。
见 https://msdn.microsoft.com/zh-cn/library/zxt5ahzw(v=vs.80).aspx
他给出的示例代码是
static void EndWriteCallback(IAsyncResult asyncResult)
{
    State tempState = (State)asyncResult.AsyncState;
    FileStream fStream = tempState.FStream;
    fStream.EndWrite(asyncResult);

    // Asynchronously read back the written data.
    fStream.Position = 0;
    asyncResult = fStream.BeginRead(
        tempState.ReadArray, 0 , tempState.ReadArray.Length, 
        new AsyncCallback(EndReadCallback), tempState);

    // Concurrently do other work, such as 
    // logging the write operation.
}
无论你再怎么封装,基础代码也就这么多

从工作流程而言,你没有搞清楚同步和异步的概念