.NET的NetworkStream读取缓慢缓慢、NET、NetworkStream

2023-09-04 00:59:57 作者:薇夢纪蓝

我有一些网络code来处理arbitary TCP连接。

这一切似乎按预期工作,但似乎慢。当我异形code中的似乎用上好的600毫秒NetworkStream.Read(),我不知道如何改进它。我拨弄着缓冲区大小和一个巨大的缓冲区之间交替读取所有数据一气呵成还是小的,应连接的数据到一个StringBuilder。目前我使用的客户端是一个网络浏览器,但这个code是通用的,它很可能不是HTTP正在发送给它的数据。任何想法?

我的code是这样的:

 公共无效StartListening()
    {
        尝试
        {
            锁定(oSyncRoot)
            {
                oTCPListener =新的TcpListener(oIPaddress,NPORT);

                //启动服务器
                oTCPListener.Start();

                //设置监听位
                bIsListening = TRUE;
            }

            //输入监听循环。
            做
            {
                //等待连接
                TcpClient的newClient = oTCPListener.AcceptTcpClient();

                //排队的请求采取客户关怀
                oThreadPool.QueueUserWorkItem(新WaitCallback(ProcessConnection),newClient);
            }
            而(bIsListening);
        }
        赶上(SocketException SE)
        {
            Logger.Write(新TCPLogEntry(SocketException:+ se.ToString()));
        }
        最后
        {
            // 关掉它
            的stopListening();
        }
    }

    私人无效ProcessConnection(对象OCLIENT)
    {

        TcpClient的oTCPClient =(TcpClient的)OCLIENT;
        尝试
        {
            byte []的abBuffer =新的字节[1024];
            StringBuilder的sbReceivedData =新的StringBuilder();

            使用(的NetworkStream oNetworkStream = oTCPClient.GetStream())
            {
                //设置的初始读超时设置nInitialTimeoutMS允许连接
                oNetworkStream.ReadTimeout = nInitialTimeoutMS;

                INT nBytesRead = 0;

                做
                {
                    尝试
                    {
                        布尔bDataAvailable = oNetworkStream.DataAvailable;

                        而(!bDataAvailable)
                        {
                           Thread.sleep代码(5);
                           bDataAvailable = oNetworkStream.DataAvailable;
                        }

                        nBytesRead = oNetworkStream.Read(abBuffer,0,abBuffer.Length);

                        如果(nBytesRead大于0)
                        {
                            //转换数据字节为ASCII字符串和追加
                            sbReceivedData.Append(Encoding.UTF8.GetString(abBuffer,0,nBytesRead));
                            //减少读取超时到nReadTimeoutMS第二,现在的数据进来
                            oNetworkStream.ReadTimeout = nReadTimeoutMS;

                        }
                    }
                    赶上(IOException异常)
                    {
                        //读超时,所有数据被检索
                        nBytesRead = 0;
                    }
                }
                而(nBytesRead大于0);

                //将数据发送到回调和获得响应回
                byte []的abResponse = oClientHandlerDelegate(sbReceivedData.ToString(),oTCPClient);
                如果(abResponse!= NULL)
                {
                    oNetworkStream.Write(abResponse,0,abResponse.Length);
                    oNetworkStream.Flush();
                }
            }
        }
        赶上(例外五)
        {
            Logger.Write(新TCPLogEntry(捕获异常+ e.StackTrace));
        }
        最后
        {
            //停止谈论到客户端
            如果(oTCPClient!= NULL)
            {
                oTCPClient.Close();
            }
        }
    }
 

编辑:我得到大约在两个完全独立的机器(我的XP开发机,并在结肠一个2003箱)相同的数字。我已经把一些时间到周围的相关部分(使用System.Diagnostic.StopWatch)在code和转储到一个日志:

2009年7月6日下午3点44分五十秒:调试:虽然DataAvailable了0毫秒
2009年7月6日下午3点44分五十秒:调试:读了531毫秒
2009年7月6日下午3点44分五十秒:调试:ProcessConnection了577毫秒

解决方案 VCSA 6.5 fails to start File System Check and Network Service

在一些研究似乎加快这唯一的办法就是打破后的第一个X字节被读取。延迟似乎是对第二读取。如果我更改缓冲区为8096字节(可能是我最大的应用程序将在任何一个去发送),打破这里:

 如果(nBytesRead大于0)
        {
             //转换数据字节为ASCII字符串和追加
             sbReceivedData.Append(Encoding.UTF8.GetString(abBuffer,0,nBytesRead));

            如果(bTurboMode)
            {
                  打破;
            }
            其他
            {
                  //减少读取超时到nReadTimeoutMS第二,现在的数据进来
                  oNetworkStream.ReadTimeout = nReadTimeoutMS;
            }
        }
 

那么响应时间的推移,从600毫秒到80ms左右。这是一个可以接受的解决方案,我现在。我可以从调用应用程序,并加快速度吧大幅切换bTurboMode对于这种情况

I've got some network code to process an arbitary TCP connection.

It all seems to work as expected but seems slow. When i've profiled the code the it seems to spend a good 600 ms in NetworkStream.Read() and I'm wondering how to improve it. I've fiddled with the buffer sizes and alternated between a massive buffer to read all of the data in one go or a small one which should concatenate the data into a StringBuilder. Currently the client i'm using is a web-browser but this code is generic and it may well not be HTTP data that is being sent to it. Any ideas?

My code is this:

    public void StartListening()
    {
        try
        {
            lock (oSyncRoot)
            {
                oTCPListener = new TcpListener(oIPaddress, nPort);

                // fire up the server
                oTCPListener.Start();

                // set listening bit
                bIsListening = true;
            }

            // Enter the listening loop.
            do
            {
                // Wait for connection
                TcpClient newClient = oTCPListener.AcceptTcpClient();

                // queue a request to take care of the client
                oThreadPool.QueueUserWorkItem(new WaitCallback(ProcessConnection), newClient);
            }
            while (bIsListening);
        }
        catch (SocketException se)
        {
            Logger.Write(new TCPLogEntry("SocketException: " + se.ToString()));
        }
        finally
        {
            // shut it down
            StopListening();
        }
    }

    private void ProcessConnection(object oClient)
    {

        TcpClient oTCPClient = (TcpClient)oClient;
        try
        {
            byte[] abBuffer = new byte[1024];
            StringBuilder sbReceivedData = new StringBuilder();

            using (NetworkStream oNetworkStream = oTCPClient.GetStream())
            {
                // set initial read timeout to nInitialTimeoutMS to allow for connection
                oNetworkStream.ReadTimeout = nInitialTimeoutMS;

                int nBytesRead = 0;

                do
                {
                    try
                    {
                        bool bDataAvailable = oNetworkStream.DataAvailable;

                        while (!bDataAvailable)
                        {
                           Thread.Sleep(5);
                           bDataAvailable = oNetworkStream.DataAvailable;
                        }

                        nBytesRead = oNetworkStream.Read(abBuffer, 0, abBuffer.Length);

                        if (nBytesRead > 0)
                        {
                            // Translate data bytes to an ASCII string and append
                            sbReceivedData.Append(Encoding.UTF8.GetString(abBuffer, 0, nBytesRead));
                            // decrease read timeout to nReadTimeoutMS second now that data is coming in
                            oNetworkStream.ReadTimeout = nReadTimeoutMS;

                        }
                    }
                    catch (IOException)
                    {
                        // read timed out, all data has been retrieved
                        nBytesRead = 0;
                    }
                }
                while (nBytesRead > 0);

                //send the data to the callback and get the response back
                byte[] abResponse = oClientHandlerDelegate(sbReceivedData.ToString(), oTCPClient);
                if (abResponse != null)
                {
                    oNetworkStream.Write(abResponse, 0, abResponse.Length);
                    oNetworkStream.Flush();
                }
            }
        }
        catch (Exception e)
        {
            Logger.Write(new TCPLogEntry("Caught Exception " + e.StackTrace));
        }
        finally
        {
            // stop talking to client
            if (oTCPClient != null)
            {
                oTCPClient.Close();
            }
        }
    }

Edit: I get roughly the same figures on two entirely seperate machines (my XP development machine and a 2003 box in a colo). I've put some timing into the code around the relevant parts (using System.Diagnostic.StopWatch) and dump it to a log:

7/6/2009 3:44:50 PM : Debug : While DataAvailable took 0 ms
7/6/2009 3:44:50 PM : Debug : Read took 531 ms
7/6/2009 3:44:50 PM : Debug : ProcessConnection took 577 ms

解决方案

After some more research it seems that the only way to speed this up is to break after the first x bytes have been read. The delay seems to be on the second read. If I change the buffer to be 8096 bytes (probably the max my application will be sent at any one go) and break here:

        if (nBytesRead > 0)
        {
             // Translate data bytes to an ASCII string and append
             sbReceivedData.Append(Encoding.UTF8.GetString(abBuffer, 0, nBytesRead));

            if (bTurboMode)
            {
                  break;
            }
            else
            {
                  // decrease read timeout to nReadTimeoutMS second now that data is coming in
                  oNetworkStream.ReadTimeout = nReadTimeoutMS;
            }
        }

Then the response time goes from 600ms to about 80ms. This is an acceptable solution for me currently. I can toggle the bTurboMode from the calling application and speed things up substantially for this case