代码之家  ›  专栏  ›  技术社区  ›  David Anderson

套接字断开连接行为

  •  2
  • David Anderson  · 技术社区  · 15 年前

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

        /// <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 Productions保留所有权利。] // * ** * ** * ** * ** * ** * ** * ** * ** * ** * ** * ** * ** * **

    命名空间CipherBox.Drivers{ 使用系统; 使用System.Collections.Generic; 使用System.Linq; 使用System.Text; 使用系统。线程; 使用System.Net.Sockets; 使用System.Net; 使用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
    }
    

    }

    4 回复  |  直到 15 年前
        1
  •  3
  •   Luis G. Costantini R.    15 年前

    你必须调用socket.shutdown(Both)参数可以是Send、Receive或Both,这取决于你想如何结束连接。此函数向客户端发送必要的TCP消息以关闭连接。

        2
  •  1
  •   David Anderson    15 年前

    我通过在集合中存储对每个连接的引用并使用客户端套接字关闭所有连接来更正了该问题。

        private void DestructConnections() {
            foreach (Socket connection in connections) {
                connection.Shutdown(SocketShutdown.Both);
                connection.Close();
            }
            connections.Clear();
        }
    
        3
  •  0
  •   basarat    15 年前

    建议在使用面向连接的套接字时,应在关闭连接之前调用Shutdown。关机用于通知通信结束。Close用于释放托管/非托管资源
    资源:
    http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.shutdown.aspx

        4
  •  0
  •   Eir Nym    15 年前

    使用任何语言的套接字时,都会创建只侦听和接受连接的服务器套接字,并且有许多p2p套接字可以发送和/或接收数据。

    所以你的答案是在微软Windows,BSD,Linux等系统中设计sockets子系统。

    推荐文章