我有一个相当通用的C#套接字服务器,它使用套接字类的异步方法 - BeginAccept(),BeginReceive()等。这个服务器在运行Win Server 2003的许多客户站点上已经运行了4年。最近我把它安装在64位的Windows Server 2008 R2服务器上。在第一个客户端连接并在accept处理程序中发出BeginReceive()和BeginAccept()调用之前,一切看起来都很好。发生这种情况时,CPU使用率会达到100%并保持不变,直到我关闭侦听套接字。
不确定是否重要,但服务器正在虚拟机中运行。
做了很多测试,但似乎没有任何帮助。使用Process Explorer,我可以看到在BeginReceive()/ BeginAccept()调用后不久就会出现两个线程,并且它们正在消耗处理器。不幸的是,我无法在Win7 64位工作站上重现此问题。
我做了很多研究,到目前为止我发现的所有内容都是以下两篇KB文章,暗示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);
}
}
答案 0 :(得分:2)
问题是由于在设置侦听器套接字时对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 :(得分:1)
我知道你发现SetupServerSocket()的“Wire Performance”文章 - 如果你有快速的新客户端连接,原来的10x for循环是支持10个监听线程。您已将其更改为一个侦听器。如果Win2k8r2有这样的错误,也许这是唯一可行的解决方案。您可能希望确保在客户端中具有强大的连接重试代码。
使用.NET中的高性能套接字更加接近线路 http://msdn.microsoft.com/en-us/magazine/cc300760.aspx