2010-11-24 60 views
2

我有一个小的方法来禁用我的套接字来监听传入的连接。套接字断开行为

/// <summary> 
    /// Stops and disables the service 
    /// </summary> 
    public void Disable() { 
     if (Running) { 
      try { 
       thread.Abort(); 
      } 
      catch (System.Threading.ThreadAbortException) { 
       // This catch is not raised. 
       // We can simply process our closing of the socket and nullify the thread 
      } 
      finally { 
       socket.Close(); 
       socket = null; 
       thread = null; 
       if (socket == null && thread == null) { 
        m_Running = false; 
        OnDisabled(this, new EventArgs()); 
       } 
      } 
     } 
    } 

我的问题是,即使在我调用Close()并使套接字无效后,客户端仍保持连接状态。我使用netstat -a运行了一个检查,并显示客户端仍然连接。

TCP 127.0.0.1:2161   activate:7777   ESTABLISHED 
TCP 127.0.0.1:7777   activate:2161   ESTABLISHED 

7777是我的主机套接字侦听的端口。所以我的问题是,关闭主机套接字后,为什么客户端套接字不能断开连接。他们如何保持连接到一个空的套接字,并不再听取?

一些额外的信息

/// <summary> 
    /// Enables and runs the service 
    /// </summary> 
    public void Enable() { 
     if (!Running) { 
      ThreadStart start = new ThreadStart(RunServiceAsync); 
      thread = new Thread(start); 
      thread.IsBackground = true; 
      thread.Start(); 
      m_Running = true; 
      OnEnabled(this, new EventArgs()); 
     } 
    } 

上述方法是线程的创建方式。一切正常,线程,连接;唯一的问题是,当我关闭套接字(主机),并取消它的客户端仍然连接到它。

问题是,一旦主机套接字关闭并设置为空,客户端连接到了什么?它们不应该断开连接并且失去与主机的连接,因为主机套接字已关闭?

以下是完整的代码,以帮助

// ********************************************************************* 

// [DCOM制作] // [版权所有(C)DCOM制作全部保留。权利] // * * * * ** * ** * ** * ** * ** * ** * ** * ** * ** * ** * ** * **

命名空间使用CipherBox.Drivers { 系统; using System.Collections.Generic;使用System.Linq的 ; using System.Text;使用System.Threading的 ;使用System.Net.Sockets的 ;使用System.Net的 ; using System.ComponentModel;使用CipherBox.Objects的 ;

/// <summary> 
/// Driver that manages the network connection between the master program and clients, also provides informational events 
/// </summary> 
public class NetworkDriver : IDriver { 

    #region Fields 

    private Socket socket; 
    private Thread thread; 

    #endregion 

    #region Properties 

    private int m_Port = 7777; 
    /// <summary> 
    /// Gets the port that the network runs on. The default port is 7777. 
    /// </summary> 
    public int Port { 
     get { 
      return m_Port; 
     } 
    } 

    #endregion 

    #region Events 

    /// <summary> 
    /// Delegate for when a node connects to the service 
    /// </summary> 
    public delegate void NodeConnectedEventHandler(object sender, NetworkNodeEventArgs e); 
    /// <summary> 
    /// Triggers when an node connects to the service 
    /// </summary> 
    public event NodeConnectedEventHandler NodeConnected; 
    /// <summary> 
    /// Event callback for NodeConnected 
    /// </summary> 
    private void OnNodeConnected(object sender, NetworkNodeEventArgs e) { 
     if (NodeConnected != null) { 
      foreach (NodeConnectedEventHandler handler in NodeConnected.GetInvocationList()) { 
       ISynchronizeInvoke syncInvoke = handler.Target as ISynchronizeInvoke; 
       if (syncInvoke != null && syncInvoke.InvokeRequired) { 
        syncInvoke.Invoke(handler, new object[] { handler.Target, e }); 
       } 
       else { 
        NodeConnected(this, e); 
       } 
      } 
     } 
    } 

    /// <summary> 
    /// Delegate for when a node disconnects from the service 
    /// </summary> 
    public delegate void NodeDisconnectedEventHandler(object sender, NetworkNodeEventArgs e); 
    /// <summary> 
    /// Triggers when an node disconnects from the service 
    /// </summary> 
    public event NodeDisconnectedEventHandler NodeDisconnected; 
    /// <summary> 
    /// Event callback for NodeDisconnected 
    /// </summary> 
    private void OnNodeDisconnected(object sender, NetworkNodeEventArgs e) { 
     if (NodeDisconnected != null) { 
      foreach (NodeDisconnectedEventHandler handler in NodeDisconnected.GetInvocationList()) { 
       ISynchronizeInvoke syncInvoke = handler.Target as ISynchronizeInvoke; 
       if (syncInvoke != null && syncInvoke.InvokeRequired) { 
        syncInvoke.Invoke(handler, new object[] { handler.Target, e }); 
       } 
       else { 
        NodeDisconnected(this, e); 
       } 
      } 
     } 
    } 

    #endregion 

    #region Methods 

    private NetworkNode FillNode(Socket socket) { 
     StringBuilder stream = new StringBuilder(); 
     byte[] buffer = new byte[4096]; 
     int bytesReceived = -1; 
     do { 
      try { 
       bytesReceived = socket.Receive(buffer, 0, buffer.Length, SocketFlags.None); 
      } 
      catch (System.Net.Sockets.SocketException) { 
       return null; 
      } 
      finally { 
       stream.Append(Encoding.ASCII.GetString(buffer, 0, bytesReceived)); 
      } 
     } while (!stream.ToString().EndsWith("\r\n\r\n")); 
     string[] packet = stream.ToString().Split(new string[] { "\r\n" }, StringSplitOptions.None); 
     if (packet.Length == 9) { 
      if (packet[0].ToLower() == "CipherBox".ToLower()) { 
       NetworkNode node = new NetworkNode(); 
       node.Domain = packet[1]; 
       node.LocalIP = IPAddress.Parse(packet[2]); 
       node.MachineName = packet[3]; 
       node.Platform = packet[4]; 
       node.RemoteIP = IPAddress.Parse(packet[5]); 
       node.Workgroup = packet[6]; 
       node.Socket = socket; 
       return node; 
      } 
      else { 
       return null; 
      } 
     } 
     else { 
      return null; 
     } 
    } 

    private bool IsDisconnected(Socket socket) { 
     bool connected = false; 
     try { 
      connected = !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0); 
     } 
     catch (System.Net.Sockets.SocketException) { 
      connected = false; 
     } 
     return !connected; 
    } 

    private void MonitorNode(NetworkNode node) { 
     ParameterizedThreadStart start = new ParameterizedThreadStart(MonitorNodeAsync); 
     Thread thread = new Thread(start); 
     thread.IsBackground = true; 
     thread.Start(node); 
    } 

    private void MonitorNodeAsync(object obj) { 
     NetworkNode node = obj as NetworkNode; 
     while (Running || node != null) { 
      if (IsDisconnected(node.Socket)) { 
       node.Socket.Shutdown(SocketShutdown.Both); 
       node.Socket.Close(); 
       node.Socket = null; 
       OnNodeDisconnected(null, new NetworkNodeEventArgs(node)); 
       return; 
      } 
      else { 
       Thread.Sleep(1000); 
      } 
     } 
    } 

    private void RunServiceAsync() { 
     socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     IPEndPoint localEP = new IPEndPoint(IPAddress.Any, Port); 
     socket.Bind(localEP); 
     socket.Listen(1); 
     do { 
      Socket client; 
      try { 
       client = socket.Accept(); 
      } 
      catch (System.Net.Sockets.SocketException) { 
       continue; 
      } 
      NetworkNode node = FillNode(client); 
      if (node != null) { 
       OnNodeConnected(null, new NetworkNodeEventArgs(node)); 
       MonitorNode(node); 
      } 
     } while (Running); 
    } 

    /// <summary> 
    /// Sets the port that the network runs on 
    /// </summary> 
    /// <param name="port">The port to set</param> 
    public void SetPort(int port) { 
     m_Port = port; 
    } 

    #endregion 

    #region IDriver Members 

    /// <summary> 
    /// Triggered when the network driver is disabled 
    /// </summary> 
    public event EventHandler<EventArgs> Disabled; 
    /// <summary> 
    /// Event callback for Disabled 
    /// </summary> 
    private void OnDisabled(object sender, System.EventArgs e) { 
     if (Disabled != null) { 
      foreach (EventHandler<EventArgs> handler in Disabled.GetInvocationList()) { 
       ISynchronizeInvoke syncInvoke = handler.Target as ISynchronizeInvoke; 
       if (syncInvoke != null && syncInvoke.InvokeRequired) { 
        syncInvoke.Invoke(handler, new object[] { handler.Target, e }); 
       } 
       else { 
        Disabled(this, e); 
       } 
      } 
     } 
    } 

    /// <summary> 
    /// Triggered when the network driver is enabled 
    /// </summary> 
    public event EventHandler<EventArgs> Enabled; 
    /// <summary> 
    /// Event callback for Enabled 
    /// </summary> 
    private void OnEnabled(object sender, System.EventArgs e) { 
     if (Enabled != null) { 
      foreach (EventHandler<EventArgs> handler in Enabled.GetInvocationList()) { 
       ISynchronizeInvoke syncInvoke = handler.Target as ISynchronizeInvoke; 
       if (syncInvoke != null && syncInvoke.InvokeRequired) { 
        syncInvoke.Invoke(handler, new object[] { handler.Target, e }); 
       } 
       else { 
        Enabled(this, e); 
       } 
      } 
     } 
    } 

    /// <summary> 
    /// Stops and disables the service 
    /// </summary> 
    public void Disable() { 
     if (Running) { 
      try { 
       thread.Abort(); 
      } 
      catch (System.Threading.ThreadAbortException) { 
       // This catch is not raised. 
       // We can simply process our closing of the socket and nullify the thread 
      } 
      finally { 
       socket.Close(); 
       socket = null; 
       thread = null; 
       if (socket == null && thread == null) { 
        m_Running = false; 
        OnDisabled(this, new EventArgs()); 
       } 
      } 
     } 
    } 

    /// <summary> 
    /// Enables and runs the service 
    /// </summary> 
    public void Enable() { 
     if (!Running) { 
      ThreadStart start = new ThreadStart(RunServiceAsync); 
      thread = new Thread(start); 
      thread.IsBackground = true; 
      thread.Start(); 
      m_Running = true; 
      OnEnabled(this, new EventArgs()); 
     } 
    } 

    private bool m_Running = false; 
    /// <summary> 
    /// Gets a System.Boolean value indicating whether the service is running or not 
    /// </summary> 
    public bool Running { 
     get { 
      return m_Running; 
     } 
    } 

    #endregion 
} 

}

+0

相关? http://stackoverflow.com/questions/3137274/thread-abort-doesnt-seem-to-throw-a-threadabortexception-because-of-acceptsocket – Lazlo 2010-11-24 04:48:30

+0

哇......这个`线程`被中止了什么?这是当前线程吗?如果没有,那么为什么你将它包装到`ThreadAbortException`处理程序中? `thread`和`socket`的范围是什么?我假设示例代码是针对“主持人”的......您究竟如何倾听?你使用`Socket.Accept()`?这创建另一个套接字对象。关闭监听器就是这样 - 停止监听新连接。 – 2010-11-24 04:51:21

回答

3

呦必须调用socket.shutdown(两者)参数可以发送,接收或两者取决于你喜欢如何结束连接。该功能将必要的TCP消息发送到客户端以关闭连接。

0

当你用任何语言插槽工作,创建服务器套接字只倾听和接受连接,有很多是P2P套接字来发送和/或接收数据。

所以你的答案是Microsoft Windows,BSD,Linux等

1

插座子系统的设计,我通过存储引用集合中的每个连接和关闭使用该客户端套接字的所有连接修正了该问题。

private void DestructConnections() { 
     foreach (Socket connection in connections) { 
      connection.Shutdown(SocketShutdown.Both); 
      connection.Close(); 
     } 
     connections.Clear(); 
    }