首页 文章

套接字断开行为

提问于
浏览
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是我的主机套接字侦听的端口 . 所以我的问题是,关闭主机套接字后,为什么客户端套接字不会断开连接 . 它们如何保持连接到一个null的套接字,而不再是监听?

Some additional info

/// <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());
        }
    }

上面的方法是如何创建线程 . 一切都很好,线程,连接;唯一的问题是当我关闭套接字(主机),并使其无效时,客户端仍然连接到它 .

问题是,一旦主机套接字关闭并设置为null,客户端连接到什么?它们是否应该断开并断开与主机的连接,因为主机插座已关闭?

Here is the full code to help

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

// [DCOM Productions] // [版权所有(C)DCOM Productions保留所有权利 . ] // *******************************************

namespace CipherBox.Drivers {using System;使用System.Collections.Generic;使用System.Linq;使用System.Text;使用System.Threading;使用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 回答

  • 0

    哟必须调用socket.shutdown(两者)参数可以是Send,Receive或Both,具体取决于您希望结束连接的方式 . 此函数将必要的TCP消息发送到客户端以关闭连接 .

  • 0

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

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

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

  • 1

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

    所以你的答案是在Microsoft Windows,BSD,Linux等设计套接字子系统 .

相关问题