Как повторно использовать сокет после его принудительного закрытия? - PullRequest
0 голосов
/ 03 июня 2019

Итак, в настоящее время я изучаю Сокеты , и мне удалось создать Сервер, который принимает соединения, и Клиент, который подключается к Серверу.

Когда Client подключается к Server Серверу, он реагирует, показывая MessageBox, говоря "Client Connected". Супер просто и работает как шарм.

Однако, если я затем закрою клиент, он, как правило, выдаст SocketException, объясняющий, что «Эй, клиент был принудительно закрыт», что понятно, довольно сложно получить какие-либо данные, когда соединение разорвано.

Итак, я реализовал функцию Socket.Poll для определения состояния сокета, и после этого он перестал генерировать исключение, потому что теперь я его обрабатываю. Я никогда не говорил, что сделал это хорошо, просто с этим справляются, и я обращаюсь за помощью.

Теперь, если Client аварийно завершает работу или принудительно закрывается, он не выдает ошибку, но когда я пытаюсь подключиться снова, Server не реагирует и не вызывает функцию Callback.

Client подключается к Server, но Server не показывает MessageBox, к которому подключен Client. Почему это так?

Вот так я и начинаю Сервер

private void StartUp()
        {
            ServerSocket.Bind(7777);
            ServerSocket.Listen(500);
            ServerSocket.AcceptConnectionAsync();
...

А вот и объект ServerSocket

class ServerSocket
    {
        private static readonly Socket _SERVER_SOCKET = new Socket(SocketType.Stream, ProtocolType.Tcp);
        private static byte[] RECEIVED_BUFFER;

        public ServerSocket()
        {

        }

        public static void Bind(int port)
        {
            _SERVER_SOCKET.Bind(new IPEndPoint(IPAddress.Any, port));
        }

        public static void Listen(int backLog)
        {
            _SERVER_SOCKET.Listen(backLog);
        }


        public static void AcceptConnectionAsync()
        {
            _SERVER_SOCKET.BeginAccept(ConnectionAcceptedCallback, null);
        }

        private static void ConnectionAcceptedCallback(IAsyncResult ar)
        {
            //Once this function gets invoked we can stop that specific one
            //and store the socket instance in a variable.
            var ACCEPTED_SOCKET = _SERVER_SOCKET.EndAccept(ar);

            MessageBox.Show("Client connected.");

            //Clear the BUFFER before passing it into the callback
            RECEIVED_BUFFER = new byte[1024];
            //Starts receiving data and store it in the BUFFER
            //Once data has been received, invoke the callback.
            ACCEPTED_SOCKET.BeginReceive(RECEIVED_BUFFER, 0, RECEIVED_BUFFER.Length, SocketFlags.None,
                ReceivedDataCallback, ACCEPTED_SOCKET);

        }

        private static void ReceivedDataCallback(IAsyncResult ar)
        {
            //Null cast the AsyncResult parameter as a Socket.
            var CLIENT_SOCKET = ar.AsyncState as Socket;
            if (!CLIENT_SOCKET.Poll(1000, SelectMode.SelectRead))
            {
                //Used to theow an exception if the client forcibly closed.
                //but it stopped since I'm using "Poll" now.
                var BUFFER_SIZE = CLIENT_SOCKET.EndReceive(ar);

                var PACKET = new byte[BUFFER_SIZE];

                Array.Copy(RECEIVED_BUFFER, PACKET, PACKET.Length);

                //Handle the packet.

                MessageBox.Show($"{CLIENT_SOCKET.RemoteEndPoint}: {Encoding.ASCII.GetString(PACKET)}");
            }
            else
            {
                CLIENT_SOCKET.Disconnect(false);
            }
        }
    }

А вот так я запускаю клиент

static void Main(string[] args)
        {
            ClientSocket.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 7777));


            while (true)
                Console.Read();
        }

И объект ClientSocket

class ClientSocket
    {
        private static readonly Socket CLIENT_SOCKET =  new Socket(SocketType.Stream, ProtocolType.Tcp);

        public ClientSocket()
        {

        }


        public static void Connect(IPEndPoint Endpoint)
        {
            CLIENT_SOCKET.Connect(Endpoint);

            if (CLIENT_SOCKET.Connected)
            {
                Console.WriteLine("Connected to the server.");

                CLIENT_SOCKET.Send(Encoding.ASCII.GetBytes("Hello World!"), SocketFlags.None);
            }
        }
    }
...