如何使用NetworkStream.BeginRead读取所有请求的数据?

时间:2013-05-13 10:44:12

标签: c# tcpclient networkstream beginread

有一个异步服务器代码。客户端发送标题 - 数据块+数据块大小。

服务器首先异步读取Header,然后读取数据块。

在我读取数据块后,我需要运行BeginRead for Header读取部分,以使线程异步。

问题:

当我得到DataCallBack时,排成一行:

  

int bytesRead = ns.EndRead(result);

我得到的不是我要求阅读的所有缓冲区

  

mc.Client.GetStream()。BeginRead(mc.DataBuffer,0,size,new AsyncCallback(DataCallBack),mc);

如果客户端发送1MB数据,我可以获得不同数量的“bytesRead”。

问题:

如何强制“BeginRead”从连接中读取所有数据。它应该导致Header的新循环 - 数据。

MyClient - 只需在TcpClient上包装;

CODE:

    public  void DoAcceptTcpClientCallback(IAsyncResult ar)
    {
        TcpListener listener = (TcpListener)ar.AsyncState;
        TcpClient client = listener.EndAcceptTcpClient(ar);
        client.NoDelay = false;
       // client.ReceiveBufferSize = 1024*1024;
        listener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback), listener);
        MyClient mc = new MyClient(client);
        ContinueRead(0,mc);
    }

    public void ContinueRead(int size, MyClient mc)
    {
        if (size != 0)
        {
            mc.DataBuffer = new byte[size];
            mc.Client.GetStream().BeginRead(mc.DataBuffer, 0, size, new AsyncCallback(DataCallBack), mc);
        }
        mc.Client.GetStream().BeginRead(mc.HeaderBuffer, 0, 4, new AsyncCallback(HeaderCallBack), mc);

    }

    private void HeaderCallBack(IAsyncResult result)
    {
        MyClient mc = (MyClient)result.AsyncState;
        NetworkStream ns = mc.Stream;
        int bytesRead = ns.EndRead(result);
        if (bytesRead == 0)
            throw new Exception();
        mc.TotalLengs =  BitConverter.ToInt32(mc.HeaderBuffer, 0);
        ContinueRead(mc.TotalLengs, mc);

    }
    private void DataCallBack(IAsyncResult result)
    {
        MyClient mc = (MyClient)result.AsyncState;
        NetworkStream ns = mc.Stream;
        int bytesRead = ns.EndRead(result);
        if (bytesRead == 0)
            throw new Exception();

糟糕的代码 - 让ASYNC阅读 - 同步

        while (bytesRead < mc.TotalLengs)
        {
            bytesRead += ns.Read(mc.DataBuffer, bytesRead, mc.TotalLengs - bytesRead);
        }

END BAD CODE

        ContinueRead(0, mc);
        ProcessPacket(mc.DataBuffer, mc.IP);
    }

1 个答案:

答案 0 :(得分:4)

“如果客户端发送1MB数据,我可以获得不同数量的”bytesRead“。”

是的......这就是TCP的工作原理。你无法改变这一点。 TCP保证数据包的顺序,而不是它们的分组方式。数据包传输路由的硬件和流量条件决定了数据的分组(或未分组)。

“如何强制”BeginRead“读取连接中的所有数据。”

TCP不知道发送了多少数据。就它而言,连接只是一个无穷无尽的字节流;因此它无法读取“所有数据”,因为数据没有结束(从它的角度来看)。 TCP也没有关于您的应用程序的“完整消息”的概念。程序员需要开发一个协议,让您的应用程序知道所有数据何时发送。

如果您期望一定数量的字节,则保持EndRead()返回的值的运行总和,并在达到该幻数时停止。