Поведение разъединителя сокета - PullRequest
2 голосов
/ 24 ноября 2010

У меня есть небольшой метод, который я использую, чтобы отключить сокет, который прослушивает входящие соединения.

    /// <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 Productions] // [Copyright (C) DCOM Productions Все права защищены.] // ***************************************

namespace CipherBox.Drivers {using System;using System.Collections.Generic;использование System.Linq;используя 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
}

}

Ответы [ 4 ]

3 голосов
/ 24 ноября 2010

Вам нужно вызвать socket.shutdown (Both), параметр может быть Send, Receive или Both, в зависимости от того, как вы хотите завершить соединение. Эта функция отправляет необходимое TCP-сообщение клиенту, чтобы закрыть соединение.

1 голос
/ 24 ноября 2010

Я исправил проблему, сохранив ссылки на каждое соединение в коллекции и закрыв все соединения с помощью клиентских сокетов.

    private void DestructConnections() {
        foreach (Socket connection in connections) {
            connection.Shutdown(SocketShutdown.Both);
            connection.Close();
        }
        connections.Clear();
    }
0 голосов
/ 24 ноября 2010

Когда вы работаете с сокетами на любом языке, вы создаете серверный сокет, который только прослушивает и принимает подключения, и имеется много p2p-сокетов для отправки и / или получения данных.

Итак, ваш ответ - разработка подсистемы сокетов в Microsoft Windows, BSD, Linux и т. Д.

0 голосов
/ 24 ноября 2010

Рекомендуется, чтобы при использовании сокета, ориентированного на соединение, вы вызывали Shutdown перед закрытием соединения.Отключение для уведомления об окончании связи.Закрытие для освобождения управляемых / неуправляемых ресурсов
Ресурс:
http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.shutdown.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...