S
S
Senture2018-10-24 23:15:59
C++ / C#
Senture, 2018-10-24 23:15:59

Client-Server UDP Socket Application?

Hello!
I can't write a client-server application on the UDP protocol using Socket.
I'm trying to build a UDP application similar to an application on the TCP protocol (PS The TCP client server application code partially consists of examples that are in the public domain), but it works for me like this:
SERVER:
1) There is a stream1 (the stock one in which the Main method works).

Main method
class Program
    {
        static ServerObject server; // Сервер
        static Thread listenThread; // Поток для прослушивания

        static void Main(string[] args)
        {
            try
            {
                server = new ServerObject();
                listenThread = new Thread(new ThreadStart(server.Listen));
                listenThread.Start(); // Старт потока
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

2) Flow2 is launched in which the waiting for connections begins.
Listen method
protected internal void Listen()
        {
            try
            {
                tcpListener = new TcpListener(IPAddress.Any, 34447);
                tcpListener.Start();
                Console.WriteLine("Сервер запущен. Ожидайте подключений...");

                while(true)
                {
                    TcpClient tcpClient = tcpListener.AcceptTcpClient();

                    ClientObject clientObject = new ClientObject(tcpClient, this);
                    Thread clientThread = new Thread(new ThreadStart(clientObject.Process));
                    clientThread.Start();
                }
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

3) After the client connects to the server, the server saves the client in the class and launches a thread3 to receive messages from the client and send it to other clients, after which the ClientObject is stored in the ServerObject class in the List<> list:
ClientObject class constructor
protected internal string Id { get; private set; }
        protected internal NetworkStream Stream { get; private set; }
        string userName;
        TcpClient client;
        ServerObject server;

        public ClientObject(TcpClient tcpClient, ServerObject serverObject)
        {
            Id = Guid.NewGuid().ToString();
            client = tcpClient;
            server = serverObject;
            serverObject.AddConnection(this);
        }

Process method in the ClientObject class
public void Process()
        {
            try
            {
                Stream = client.GetStream();
                // Получаем имя пользователя
                string message = GetMessage();
                userName = message;
                while(true)
                {
                    try
                    {
                        message = GetMessage();
                        message = String.Format("{0}: {1}", userName, message);
                        Console.WriteLine(message);
                        server.BroadcastMessage(message, this.Id);
                    }
                    catch
                    {
                        break;
                    }
                }
            }
            catch(Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

AddConnection method in ServerObject class
List<ClientObject> clients = new List<ClientObject>(); // Все подключения

        protected internal void AddConnection(ClientObject clientObject)
        {
            clients.Add(clientObject);
        }

4) When a message is received from the user, the BroadcastMessage method from the ServerObject class is called, in which the received message is sent to all connected clients except the sender itself, and the information to whom to send is contained in the List<> clients list:
BroadcastMessage method in ServerObject class
protected internal void BroadcastMessage(string message, string id)
        {
            byte[] data = Encoding.Unicode.GetBytes(message);
            for(int i = 0; i < clients.Count; i++)
            {
                if (clients[i].Id != id)
                    clients[i].Stream.Write(data, 0, data.Length);
            }
        }

CLIENT ON UNITY:
client
string userName;
    private const string host = "127.0.0.1";
    private const int port = 34447;
    public TcpClient client;
    public NetworkStream stream;

    public Text messages;
    public Text outPut;

    void Start()
    {
        Connection();
    }

    public void Connection()
    {
        userName =  "login";
        client = new TcpClient();
        try
        {
            client.Connect(host, port); // Подключение клиента
            stream = client.GetStream(); // Получаем поток


            byte[] data = Encoding.Unicode.GetBytes(userName);
            stream.Write(data, 0, data.Length);

            // Запускаем новый поток для получения данных
            Thread receiveThread = new Thread(new ThreadStart(ReceiveMessage));
            receiveThread.Start();
            outPut.text += "Добро пожаловать, " + StaticHelperScripts.login + "\n";
        }
        catch(Exception ex)
        {
            Debug.Log(ex.Message);
        }
    }

    public void SendMessage()
    {
        outPut.GetComponent<Text>().text += userName + " : " + messages.text + "\n";
        byte[] data = Encoding.Unicode.GetBytes(messages.text);
        stream.Write(data, 0, data.Length);
    }

    // получение сообщений
    public void ReceiveMessage()
    {
        while (true)
        {
            try
            {
                byte[] data = new byte[512]; // буфер для получаемых данных
                StringBuilder builder = new StringBuilder();
                int bytes = 0;
                do
                {
                    bytes = stream.Read(data, 0, data.Length);
                    builder.Append(Encoding.Unicode.GetString(data, 0, bytes));
                }
                while (stream.DataAvailable == false && bytes == 0);

                string message = builder.ToString();
                outPut.text += message + "\n";
            }
            catch(Exception ex)
            {
                outPut.text += "Подключение прервано!\n"; //соединение было прервано
                Disconnect();
                return;
            }
        }
    }

    public void Disconnect()
    {
        if (stream != null)
            stream.Close(); // Отключение потока
        if (client != null)
            client.Close(); // отключение клиента
    }


Now the actual question is what needs to be saved in order to make a list of connected clients and send messages from other clients? I understand that the UDP protocol is connectionless, so I can't figure out how to make such an application only on UDP. As well as multiplayer action (shooters) games, the UDP protocol is used, because. it safely influences ping which is very important. Question: In order to send a message via UDP, a port must be open, which is not good (for example, 1k players and everyone must have port 34447 open)?

Unfortunately, the UDP protocol is difficult for me, so I apologize for the possible banality.

PS I tried to paint everything as detailed as possible, if something is not clear, ask questions, and I will answer them (if I can). And thank you so much for everything!!!

Answer the question

In order to leave comments, you need to log in

1 answer(s)
S
Sumor, 2018-10-25
@Senture

UDP and TCP are different protocols over the IP protocol.
TCP establishes a connection and "talks" between the client and server over the established connection until one of them gets bored. In the simplest case, a connection is established, the client sends a request, the server sends a response. The size of received and sent data is not limited by the packet size. There can be many packets, and there can also be many requests-responses within one connection. TCP guarantees delivery of all packets. In the sense that if there is a connection, then the data sent to you will be delivered.
UDP is essentially just sending data to some address. Whether it was processed there or not - in order for you to find out, you need additional synchronization. The size of the transmitted data is determined by the size of the packet - the maximum MTU, for Ethernet it is 1500 bytes. Maybe more or less. It is possible to send more data, but they will be divided into parts and some of them may not reach.
The analogy is something like this: TCP - telephone: the connection is established, then there is a conversation between the interlocutors. UDP - radio exchange: press PTT, speak, but you do not know if your subscriber is in the radio coverage area and whether he will hear you.
You can use the UDPClient class to implement both a UDP client and server in C#. It is the same for both the server and the client. To receive messages, the server opens a port for reading. The size of received data is limited by the receive buffer. If the data arrives, but you do not have time to process it, it is overwritten.
UDP is used to transmit data for which the time of receipt is critical, but the very fact of receipt is not critical.
To understand how packets go and a connection is established, use Wireshark or similar programs.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question