首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >System.net.Socket.beginReceive()中的高CPU使用率

System.net.Socket.beginReceive()中的高CPU使用率
EN

Stack Overflow用户
提问于 2017-05-03 03:18:46
回答 2查看 1K关注 0票数 0

我有一个服务器软件,它有一个监听套接字,然后跨越多个套接字(10 -30),然后我流数据到这些套接字。

如果我启动我的应用程序,它在我的8 vCPU虚拟机上使用了大约2-3%的cpu使用率。一段时间后,通常是1-2周,应用程序突然开始使用60-70%的cpu使用率,线程计数似乎保持稳定,不会增加。

我在我的代码上运行了我的C#分析器,它归结到以下代码行System.net.Socket.beginReceive()

我正在使用.net async sockets。下面是我的ReceiveCallBack我怀疑我不是在处理bytesRead不是>0的情况。我应该如何修改下面的函数来正确处理这种情况?

代码语言:javascript
复制
public static void ReadCallback(IAsyncResult ar)
        {
            SocketState tmpRef = null;
            try
            {
                if (ar != null)
                {
                    tmpRef = (SocketState)ar.AsyncState;
                    if (tmpRef != null)
                    {
                        // Read data from the client socket. 
                        int bytesRead = tmpRef.WorkSocket.Client.EndReceive(ar);
                        //Start Reading Again
                        tmpRef.BeginReading(tmpRef._receievCallbackAction);
                        if (bytesRead > 0)
                        {
                            // Check if we have a complete message yet
                            for (var i = 0; i < bytesRead; i++)
                            {
                                if (tmpRef._receiveBuffer[i] == 160)
                                {
                                    var tmpBuffer = new byte[i];
                                    Array.Copy(tmpRef._receiveBuffer, tmpBuffer, i);
                                    //Execute callback
                                    tmpRef._receievCallbackAction(tmpBuffer);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                if (tmpRef != null)
                {
                    //Call callback with null value to indicate a failier
                    tmpRef._receievCallbackAction(null);
                }
            }
        }

完整代码:(对不起,我不想弄脏这篇文章) https://www.dropbox.com/s/yqjtz0r3ppgd11f/SocketState.cs?dl=0

EN

回答 2

Stack Overflow用户

发布于 2017-05-03 03:58:07

问题是,如果你没有足够的字节,但你的代码一直在旋转,等待下一个字节出现。

您需要做的是创建一个在调用之间存活的messageBuffer,并对其进行写入,直到获得所需的所有数据。此外,根据代码的外观,您有机会在复制所有数据之前覆盖tmpRef._receiveBuffer,如果您共享一个缓冲区,则需要在复制之后启动BeginReading

代码语言:javascript
复制
public class SocketState
{
    private readonly List<byte> _messageBuffer = new List<byte>(BufferSize);

    //...

    /// <summary>
    /// Async Receive Callback
    /// </summary>
    /// <param name="ar"></param>
    public static void ReadCallback(IAsyncResult ar)
    {
        SocketState tmpRef = null;
        try
        {
            if (ar != null)
            {
                tmpRef = (SocketState)ar.AsyncState;
                if (tmpRef != null)
                {
                    // Read data from the client socket. 
                    int bytesRead = tmpRef.WorkSocket.Client.EndReceive(ar);
                    if (bytesRead > 0)
                    {
                        //Loop over the bytes we received this read
                        for (var i = 0; i < bytesRead; i++)
                        {   
                            //Copy the bytes from the receive buffer to the message buffer.
                            tmpRef._messageBuffer.Add(tmpRef._receiveBuffer[i]);
                            // Check if we have a complete message yet
                            if (tmpRef._receiveBuffer[i] == 160)
                            {
                                //Copy the bytes to a tmpBuffer to be passed on to the callback.
                                var tmpBuffer = tmpRef._messageBuffer.ToArray();
                                //Execute callback
                                tmpRef._receievCallbackAction(tmpBuffer);
                                //reset the message buffer and keep reading the current bytes read
                                tmpRef._messageBuffer.Clear();
                            }
                        }

                        //Start Reading Again
                        tmpRef.BeginReading(tmpRef._receievCallbackAction);
                    }
                }
            }
        }
        catch (Exception e)
        {
            if (tmpRef != null)
            {
                //Call callback with null value to indicate a failier
                tmpRef._receievCallbackAction(null);
            }
        }
    }

//...
票数 1
EN

Stack Overflow用户

发布于 2017-05-03 04:06:46

您解释说问题发生在1-2周后,这在当时是很少见的。我建议您通过改进readcallback中的异常处理来引导您的研究方向。

在此异常处理中,您将使用null调用callbackAction

也许你应该考虑回答以下问题:

当使用null tmpRef._receievCallbackAction(null);

  • What调用时,捕获到某种类型的异常时,
  1. callbackAction的行为如何?如果它是一个SocketException,也许可以查看ErrorCode,这可能会给您一个indication
  2. Would可以转储堆栈跟踪,以确切地知道它出现故障的位置?

其他一些缺点: begin接收使用this作为状态对象。WorkSocket.Client.BeginReceive(_receiveBuffer, 0, BufferSize, 0, ReadCallback, this);

因此,这意味着读回调的线程安全性不能完全得到保证,因为在您还没有处理_receiveBuffer时,就会发生对BeginReading的调用。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43745620

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档