Пользовательский класс TCP Socket Server для идентификатора сокета в C # - PullRequest
0 голосов
/ 29 ноября 2018

Я смотрел на множество примеров клиент / сервер TCP, и хотел бы знать, как можно создать метод идентификации каждого клиента.Один из способов, который я знаю, - это, скажем, авторизация через логин.Я знаю, как подключиться и выполнить запрос к базе данных, но как бы мне сказать, после успешной аутентификации, взять имя пользователя и сказать, что это имя пользователя - это сокет.Пример класса или простой метод будет оценен в качестве примера.Я хочу, чтобы можно было настроить таргетинг на все подключенные клиенты по имени пользователя из базы данных индивидуально.

Пример, который я использую для сервера

 using System;

    using System.Collections.Generic;

    using System.Net;

    using System.Net.Sockets;

    using System.Text;



    namespace MultiServer

    {

        class Program

        {

            private static readonly Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            private static readonly List<Socket> clientSockets = new List<Socket>();

            private const int BUFFER_SIZE = 2048;

            private const int PORT = 100;

            private static readonly byte[] buffer = new byte[BUFFER_SIZE];



            static void Main()

            {

                Console.Title = "Server";

                SetupServer();

                Console.ReadLine(); // When we press enter close everything

                CloseAllSockets();

            }



            private static void SetupServer()

            {

                Console.WriteLine("Setting up server...");

                serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT));

                serverSocket.Listen(0);

                serverSocket.BeginAccept(AcceptCallback, null);

                Console.WriteLine("Server setup complete");

            }



            /// <summary>

            /// Close all connected client (we do not need to shutdown the server socket as its connections

            /// are already closed with the clients).

            /// </summary>

            private static void CloseAllSockets()

            {

                foreach (Socket socket in clientSockets)

                {

                    socket.Shutdown(SocketShutdown.Both);

                    socket.Close();

                }



                serverSocket.Close();

            }



            private static void AcceptCallback(IAsyncResult AR)

            {

                Socket socket;



                try

                {

                    socket = serverSocket.EndAccept(AR);

                }

                catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)

                {

                    return;

                }



               clientSockets.Add(socket);

               socket.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket);

               Console.WriteLine("Client connected, waiting for request...");

               serverSocket.BeginAccept(AcceptCallback, null);

            }



            private static void ReceiveCallback(IAsyncResult AR)

            {

                Socket current = (Socket)AR.AsyncState;

                int received;



                try

                {

                    received = current.EndReceive(AR);

                }

                catch (SocketException)

                {

                    Console.WriteLine("Client forcefully disconnected");

                    // Don't shutdown because the socket may be disposed and its disconnected anyway.

                    current.Close(); 

                    clientSockets.Remove(current);

                    return;

                }



                byte[] recBuf = new byte[received];

                Array.Copy(buffer, recBuf, received);

                string text = Encoding.ASCII.GetString(recBuf);

                Console.WriteLine("Received Text: " + text);



                if (text.ToLower() == "get time") // Client requested time

                {

                    Console.WriteLine("Text is a get time request");

                    byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());

                    current.Send(data);

                    Console.WriteLine("Time sent to client");

                }

                else if (text.ToLower() == "exit") // Client wants to exit gracefully

                {

                    // Always Shutdown before closing

                    current.Shutdown(SocketShutdown.Both);

                    current.Close();

                    clientSockets.Remove(current);

                    Console.WriteLine("Client disconnected");

                    return;

                }

                else

                {

                    Console.WriteLine("Text is an invalid request");

                    byte[] data = Encoding.ASCII.GetBytes("Invalid request");

                    current.Send(data);

                    Console.WriteLine("Warning Sent");

                }



                current.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);

            }

        }

    }

1 Ответ

0 голосов
/ 29 ноября 2018

Существует очень простое решение для этого, когда вы используете асинхронные обратные вызовы (хотя я настоятельно рекомендую перейти на более новый подход, или, что еще лучше, на существующую библиотеку - сырой TCP трудно сделать правильно).

Делегат обратного вызова может указывать на метод экземпляра.Это означает, что у вас может быть что-то вроде этого:

class Client
{
  private readonly Socket socket;
  public readonly byte[] ReceiveBuffer = new byte[BUFFFER_SIZE];

  public Client(Socket socket)
  {
    this.socket = socket;
  }

  public void ReceiveCallback(IAsyncResult AR)
  {
    // Handle the received data as usual
  }
}

А затем в вашем методе AcceptCallback просто используйте список Client вместо Socket, и последний вызов BeginReceive как таковой:

var client = new Client(socket);
socket.BeginReceive(client.ReceiveBuffer, 0, BUFFER_SIZE, SocketFlags.None, client.ReceiveCallback, 
                    socket);
clients.Add(newClient);

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

Кроме того, ObjectDisposedException, которые вы получаете, это то, что вы делаете Shutdown, сразу за которыми следует Close.Это не верно.Выключение TCP является кооперативным - вам нужно дождаться закрытия клиентского сокета, прежде чем вы вызовете Close на вашем сокете.То, что вы делаете, - это грубое прерывание соединения, прежде чем оно сможет разрешить само себя.Опять же - TCP трудно сделать правильно, вам нужно , чтобы узнать, как он работает очень тщательно.

...