开发者

Using async sockets on Windows Server 2008 R2 causes 100% CPU usage

I have a fairly generic C# socket server that uses the asynchronous methods of the socket classes - BeginAccept(), BeginReceive(), etc. This server has been working great for the last 4 years at many customer sites running Win Server 2003. Recently I installed it on a Windows Server 2008 R2 server, 64-bit. Everything looks fine until the first client connects and issues a BeginReceive() and a BeginAccept() call in the accept handler. When this happens, the CPU usage spikes to 100% and stays that way until I close the listening socket.

Not sure that it matters, but the server is running in a virtual machine.

Have done a lot of testing, but nothing seems to help. Using Process Explorer, I can see that two threads are spun up shortly after the BeginReceive()/BeginAccept() calls, and they are the ones that are consuming the processor. Unfortunately, I am not able to reproduce this problem on my Win7 64-bit workstation.

I have done a lot of research, and all that I have found so far is the following two KB articles that imply that Server 2008 R2 may have an issue with the TCP/IP components, but they are only available as hot fixes: KB2465772 and KB2477730. Am reluctant to have my customer install them until I am more certain that they will fix the issu开发者_运维技巧e.

Has anyone else had this problem? If so, what did you have to do to resolve this issue?

Here is the method that I believe causes the situation:

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);
 }
}


The issue was caused by having more than one call to BeginAccept() when setting up the listener socket. Do not know why the problem only occurs on 64bit servers, but changing the code as shown below fixed the issue.

Original code:

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);
  }
}

To the following:

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);
  //}
}


I know the "Wire Performance" article where you found SetupServerSocket() - the original 10x for loop is to support 10 listen threads if you have rapid new client connections. You've changed it to one listener. Maybe that's the only possible solution if Win2k8r2 has such a bug. You might want to be sure you have robust connect retry code in your client.

Get Closer to the Wire with High-Performance Sockets in .NET http://msdn.microsoft.com/en-us/magazine/cc300760.aspx

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜