在 Windows Server 2008 R2 上使用异步套接字会导致 100% 的 CPU 使用率

Posted

技术标签:

【中文标题】在 Windows Server 2008 R2 上使用异步套接字会导致 100% 的 CPU 使用率【英文标题】:Using async sockets on Windows Server 2008 R2 causes 100% CPU usage 【发布时间】:2011-07-01 02:15:18 【问题描述】:

我有一个相当通用的 C# 套接字服务器,它使用套接字类的异步方法 - BeginAccept()、BeginReceive() 等。过去 4 年,该服务器在许多运行 Win Server 2003 的客户站点上运行良好. 最近我在一台Windows Server 2008 R2 服务器上安装了它,64 位。在第一个客户端连接并在接受处理程序中发出 BeginReceive() 和 BeginAccept() 调用之前,一切看起来都很好。发生这种情况时,CPU 使用率会飙升至 100% 并保持这种状态,直到我关闭侦听套接字。

不确定是否重要,但服务器正在虚拟机中运行。

已经做了很多测试,但似乎没有任何帮助。使用 Process Explorer,我可以看到在 BeginReceive()/BeginAccept() 调用后不久启动了两个线程,它们是消耗处理器的线程。不幸的是,我无法在我的 Win7 64 位工作站上重现此问题。

我做了很多研究,到目前为止,我发现的只是以下两篇知识库文章,它们暗示 Server 2008 R2 可能存在 TCP/IP 组件问题,但它们仅作为热修复程序提供:KB2465772 和 KB2477730。在我更确定他们会解决问题之前,我不愿意让我的客户安装它们。

还有其他人遇到过这个问题吗?如果是这样,您必须采取什么措施来解决此问题?

这是我认为导致这种情况的方法:

private void AcceptCallback(IAsyncResult result) 
 ConnectionInfo connection = new ConnectionInfo();

 try 
    // Finish accept.
    Socket listener = (Socket)result.AsyncState;
    connection.Socket = listener.EndAccept(result);
    connection.Request = new StringBuilder(256);

    // Start receive and a new accept.
    connection.Socket.BeginReceive(connection.Buffer, 0,
       connection.Buffer.Length, SocketFlags.None,
       new AsyncCallback(ReceiveCallback), connection);

    _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), listener);

    // CPU usage spikes at 100% shortly after this...

 
 catch (ObjectDisposedException /*ode*/) 
    _log.Debug("[AcceptCallback] ObjectDisposedException");
 
 catch (SocketException se) 
    connection.Socket.Close();
    _log.ErrorFormat("[AcceptCallback] Socket Exception (0: 1 2", connection.ClientAddress, se.ErrorCode, se.Message);
 
 catch (Exception ex) 
    connection.Socket.Close();
    _log.ErrorFormat("[AcceptCallback] Exception 0: 1", connection.ClientAddress, ex.Message);
 

【问题讨论】:

我似乎有一个类似的问题,但是使用服务器 2012 R2。除了我的应用程序运行良好几个星期,然后突然我得到高 CPU 使用率。分析表明使用 cpu 的是 System.net.Socket.beginReceive() 【参考方案1】:

该问题是由于在设置侦听器套接字时对 BeginAccept() 进行了多次调用。不知道为什么这个问题只出现在 64 位服务器上,但是按照如下所示更改代码解决了这个问题。

原码:

public SetupServerSocket() 
   IPEndPoint myEndPoint = new IPEndPoint(IPAddress.Any, _port);

   // Create the socket, bind it, and start listening.
  _serverSocket = new Socket(myEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  _serverSocket.Bind(myEndPoint);
  _serverSocket.Listen((int)SocketOptionName.MaxConnections);

  for (int i = 0; i < 10; i++) 
     _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
  

致以下:

public SetupServerSocket() 
   IPEndPoint myEndPoint = new IPEndPoint(IPAddress.Any, _port);

   // Create the socket, bind it, and start listening.
  _serverSocket = new Socket(myEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  _serverSocket.Bind(myEndPoint);
  _serverSocket.Listen((int)SocketOptionName.MaxConnections);

  //for (int i = 0; i < 10; i++) 
     _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
  //

【讨论】:

【参考方案2】:

我知道您在其中找到了 SetupServerSocket() 的“Wire Performance”文章 - 如果您有快速的新客户端连接,那么原始的 10x for 循环将支持 10 个侦听线程。您已将其更改为一个侦听器。如果 Win2k8r2 有这样的错误,也许这是唯一可能的解决方案。您可能希望确保在您的客户端中有可靠的连接重试代码。

使用 .NET 中的高性能套接字更接近线路 http://msdn.microsoft.com/en-us/magazine/cc300760.aspx

【讨论】:

以上是关于在 Windows Server 2008 R2 上使用异步套接字会导致 100% 的 CPU 使用率的主要内容,如果未能解决你的问题,请参考以下文章

如何在windows server2008 r2上打开internet信息服务 iis 管理器

windows server 2008 r2 iso下载

如何在windows server 2008 r2创建web服务器

windows server2012 r2能安装sqlserver2008 R2吗

windows server 2008 r2 C盘空间不断减少!怎么清理

虚拟机windows server2008r2怎么激活