Использование асинхронных сокетов в Windows Server 2008 R2 приводит к 100% загрузке ЦП. - PullRequest
4 голосов
/ 01 июля 2011

У меня есть довольно общий сервер сокетов C #, который использует асинхронные методы классов сокетов - BeginAccept (), BeginReceive () и т. Д. Этот сервер отлично работал в течение последних 4 лет на многих сайтах клиентов, работающих под управлением Win Server 2003 Недавно я установил его на 64-битном сервере Windows Server 2008 R2. Все выглядит нормально, пока первый клиент не подключится и не вызовет вызовы BeginReceive () и BeginAccept () в обработчике принятия. Когда это происходит, загрузка процессора увеличивается до 100% и остается такой, пока я не закрою сокет прослушивания.

Не уверен, что это имеет значение, но сервер работает на виртуальной машине.

Много тестировали, но, похоже, ничего не помогло. Используя Process Explorer, я вижу, что два потока запускаются вскоре после вызовов BeginReceive () / BeginAccept (), и именно они потребляют процессор. К сожалению, я не могу воспроизвести эту проблему на моей 64-разрядной рабочей станции Win7.

Я провел много исследований, и все, что я нашел до сих пор, это следующие две статьи базы знаний, в которых подразумевается, что 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);
 }
}

Ответы [ 2 ]

2 голосов
/ 14 июля 2011

Проблема была вызвана несколькими вызовами 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);
  //}
}
1 голос
/ 25 июля 2012

Мне известна статья «Wire Performance», в которой вы нашли SetupServerSocket () - оригинальный цикл 10x for должен поддерживать 10 потоков прослушивания, если у вас быстрые новые клиентские соединения.Вы изменили это на одного слушателя.Возможно, это единственно возможное решение, если в Win2k8r2 есть такая ошибка.Возможно, вы захотите убедиться, что у вас есть надежный код повторной попытки соединения в вашем клиенте.

Будьте ближе к проводу с высокопроизводительными сокетами в .NET http://msdn.microsoft.com/en-us/magazine/cc300760.aspx

...