.net异步套接字超时检查线程安全

http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspx

从上面的msdn示例开始,我正在尝试编写一个超时检查,它将关闭非活动的客户端套接字并释放资源。

这就是我想出的。 但我不确定它是否完全是线程安全的,如果有更好的方法可以做到这一点。 我希望有人能给出一些建议。

void IO_Completed(object sender, SocketAsyncEventArgs e) { if (e.SocketError != SocketError.Success) { CloseClientSocket(e); return; } if (1  0) if (!token.Socket.SendAsync(e)) ProcessSend(e); else CloseClientSocket(e); } void ProcessSend(SocketAsyncEventArgs e) { AsyncUserToken token = (AsyncUserToken)e.UserToken; if (!token.Socket.ReceiveAsync(e)) ProcessReceive(e); } 

TimeoutCheck将每20秒执行一次。 allReadWriteArgs是一个包含所有SocketAsyncEventArgs的数组。 关闭套接字后,将使用SocketError.OperationAborted调用IO_Completed。

 void TimeoutCheck(object state) { AsyncUserToken token; int timeout = Environment.TickCount - 20000; for (int i = 0; i < allReadWriteArgs.Length; i++) { token = (AsyncUserToken)allReadWriteArgs[i].UserToken; if (token.LastActive < timeout) if (0 == Interlocked.CompareExchange(ref token.Status, 2, 0)) Interlocked.Exchange(ref token.Socket, null).Close(); } } void CloseClientSocket(SocketAsyncEventArgs e) { AsyncUserToken token = e.UserToken as AsyncUserToken; if (token.Socket != null) { try { token.Socket.Shutdown(SocketShutdown.Both); } catch (SocketException) { } token.Socket.Close(); } token.Status = 2; bufferManager.FreeBuffer(e); readWritePool.Push(e); ... } 

你的代码看起来不错。 你也可以做这样的事情:

 void _connectionActivityCheck_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { _connectionActivityCheck.Stop(); try { List connectionsToRemove = new List(); lock (_connections.SyncRoot) { IncomingConnection conn; foreach (DictionaryEntry item in _connections) { conn = (IncomingConnection)item.Value; if (conn.LastIncomingActivity.HasValue && DateTime.Now.Subtract(conn.LastIncomingActivity.Value).TotalSeconds > MaximumInactivitySeconds) connectionsToRemove.Add(conn.ConnectionId); } } if (connectionsToRemove.Count > 0) { int itemsToRemove = connectionsToRemove.Count; foreach (Guid item in connectionsToRemove) { RemoveConnection(item); } Context.Current.Logger.LogInfo(_loggerName, string.Format("{0} connections were closed due to incoming traffic inactivity", itemsToRemove)); } } catch (Exception ex) { Context.Current.Logger.LogFatal(_loggerName, "An error ocurred while checking incoming traffic.", ex); } finally { _connectionActivityCheck.Start(); } } private void RemoveConnection(Guid connectionId) { lock (_connections.SyncRoot) { try { IncomingConnection conn = _connections[connectionId] as IncomingConnection; if (conn != null) { try { conn.Dispose(); } catch { } _connections.Remove(connectionId); } } catch { } } }