2009-08-05 17 views
5

http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspx.net async सॉकेट टाइमआउट जांच धागे की सुरक्षा

MSDN उपरोक्त उदाहरण मैं एक टाइमआउट जांच करते हैं कि निष्क्रिय ग्राहक सॉकेट और मुक्त संसाधनों बंद हो जाएगा लिखने के लिए कोशिश कर रहा हूँ के साथ शुरू।

यही वह है जो मैंने साथ किया है। लेकिन मुझे यकीन नहीं है कि यह पूरी तरह से थ्रेड-सुरक्षित है और यदि ऐसा करने का एक बेहतर तरीका है। मुझे आशा है कि कोई कुछ सलाह दे सकता है।

void IO_Completed(object sender, SocketAsyncEventArgs e) 
{ 
    if (e.SocketError != SocketError.Success) 
    { 
     CloseClientSocket(e); 
     return; 
    } 

    if (1 < Interlocked.CompareExchange(ref token.Status, 1, 0)) 
     return; 

    switch (e.LastOperation) 
    { 
     case SocketAsyncOperation.Receive: 
      ProcessReceive(e); 
      break; 
     ... 
    } 

    token.LastActive = Environment.TickCount; 
    Interlocked.CompareExchange(ref token.Status, 0, 1); 
} 

void ProcessReceive(SocketAsyncEventArgs e) 
{ 
    AsyncUserToken token = (AsyncUserToken)e.UserToken; 
    if (e.BytesTransferred > 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); 
} 

टाइमआउट चेक हर 20 सेकंड में एक बार निष्पादित करेगा। allReadWriteArgs सभी सॉकेटएसिंक EventArgs के साथ एक सरणी है। सॉकेट को बंद करने के बाद IO_Completed को SocketError.OperationAborted के साथ बुलाया जाएगा।

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); 
    ... 
} 
+0

इस थोड़े पुराना है, लेकिन जो कोई भी के लिए पढ़ा है कि भविष्य में: Environment.TickCount' का उपयोग नहीं करते 'अपने आवेदन में किसी भी गणना के लिए। इसे 'इंट 32' के रूप में दर्शाया गया है जो 24.9 दिनों में चलाया जाएगा और एक पूर्णांक पूर्णांक के लिए लूप होगा और अंततः 0 लौटाएगा। इसके बजाय 'DateTime.UtcNow.Ticks' का उपयोग करें। –

उत्तर

1

आपका कोड अच्छा दिखता है। आप कुछ इस तरह कर सकते हैं, साथ ही:

void _connectionActivityCheck_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
{ 
    _connectionActivityCheck.Stop(); 

    try 
    { 
     List<Guid> connectionsToRemove = new List<Guid>(); 

     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 { } 
    } 
} 
संबंधित मुद्दे