[Unity Network Communication] Teach you how to use TCP and UDP protocols in one step

An article about Unity acting as both client and server
Communication protocol TCP, UDP
There are many repeated methods on the server side. Interested friends can write them as base classes to reduce the repetition rate.

1. Preface

Achieve sending specified commands through TCP or UDP protocol, and the receiving end performs operations related to activation of control objects;
Pay attention to read the summary at the end carefully;
Demo download

2. TCP protocol

Client (sender)

public class TCPSender : MonoBehaviour
{<!-- -->
    [Header("Destination IP Address")] public string ipAddress = "127.0.0.1";
    [Header("Target port number")] public int port = 12345;
    [Header("Send content")] public string hexCode = "FE 04 00 00 00 01 25 C5";
    [Header("Send Button")] public Button Btn_Send;
    
    private TcpClient client;
    private NetworkStream stream;

    private void Start()
    {<!-- -->
        Btn_Send.onClick.AddListener(OnButtonClick);
        client = new TcpClient(ipAddress, port);
    }

    public void OnButtonClick()
    {<!-- -->
        stream = client.GetStream();
        byte[] data = Encoding.UTF8.GetBytes(hexCode);
        stream.Write(data, 0, data.Length);
    }

    private void OnApplicationQuit()
    {<!-- -->
        client.Close();
    }
}
</code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack.png" alt ="" title="">

Server (receiving end)

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using UnityEngine;

public class TCPSever : MonoBehaviour
{<!-- -->
    private TcpListener tcpListener;

    [Header("Receive content")] public string Response;
    [Header("Whether to activate the object")] public bool IsActive;
    [Header("Object to be activated")] public GameObject[] OBJ;
    [Header("Server Port")] public int Port = 12345;
    [Header("Do you need activation time")] public bool IsActiveTime;
    [Header("Activation Time")] public float ActiveTime;

    private float ActiveTimeTemp;
    private bool isStart;
    private UnityMainThreadDispatcher mainThreadDispatcher;
    private void Start()
    {<!-- -->
        try
        {<!-- -->
            //Create TCP listener
            tcpListener = new TcpListener(IPAddress.Any, Port);
            tcpListener.Start();
            Debug.Log("TCP server has been started, waiting for client connection...");

            //Start the main thread
            mainThreadDispatcher = UnityMainThreadDispatcher.Instance;
           
            // Wait for client connection in new thread
            System.Threading.Thread acceptThread = new System.Threading.Thread(AcceptClients);
            acceptThread.Start();
        }
        catch (Exception e)
        {<!-- -->
            Debug.LogError("An error occurred: " + e.Message);
        }
    }

    private void AcceptClients()
    {<!-- -->
        while(true)
        {<!-- -->
            // Wait for client to connect
            TcpClient client = tcpListener.AcceptTcpClient();
            Debug.Log("Client connected: " + ((IPEndPoint)client.Client.RemoteEndPoint).Address);

            // Handle client requests in a new thread
            System.Threading.Thread clientThread = new System.Threading.Thread(() => HandleClient(client));
            clientThread.Start();

        }
    }

    private void HandleClient(TcpClient client)
    {<!-- -->
        try
        {<!-- -->
            NetworkStream stream = client.GetStream();
            byte[] buffer = new byte[1024];
            int bytesRead;

            while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
            {<!-- -->
                // Process the data sent by the client
                string data = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                Debug.Log("Message received: " + data);
                
                //Process the message
                Client(data);

                // You can reply to the client here
                string response = "The server has received the message: " + data;
                byte[] responseBytes = Encoding.UTF8.GetBytes(response);
                stream.Write(responseBytes, 0, responseBytes.Length);
            }

            client.Close();
        }
        catch (Exception e)
        {<!-- -->
            Debug.LogError("An error occurred while processing the client request: " + e.Message);
        }
    }

    private void OnApplicationQuit()
    {<!-- -->
        if (tcpListener != null)
        {<!-- -->
            tcpListener.Stop();
        }
    }

    public void Client(string received)
    {<!-- -->
        if (received != null)
        {<!-- -->
            //Performance
            Response = received;

            ComparisonResponse(received);
        }

    }

    //process the request
    public void ComparisonResponse(string response)
    {<!-- -->
        switch (response)
        {<!-- -->
            case "FE 04 00 00 00 01 25 C5":
                TimeOnclick();
                break;
        }
    }


    public void TimeOnclick()
    {<!-- -->
        if(IsActiveTime)
        {<!-- -->
            isStart = true;
            ActiveTimeTemp = ActiveTime;
        }
        else
        {<!-- -->
            ObjActive();
        }
    }


    public void ObjActive()
    {<!-- -->
        mainThreadDispatcher.Enqueue(() =>
        {<!-- -->
            foreach (GameObject o in OBJ)
            {<!-- -->
                o.SetActive(IsActive);
            }
        });
    }

    private void Update()
    {<!-- -->
        if(isStart)
        {<!-- -->
            ActiveTimeTemp -= Time.deltaTime;
            if (ActiveTimeTemp <= 0)
            {<!-- -->
                ObjActive();
                isStart = false;
            }
        }
    }
}

</code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack.png" alt ="" title="">

3. UDP protocol

Client (sender)

public class UdpSender : MonoBehaviour
{<!-- -->
    [Header("Destination IP Address")] public string ipAddress = "127.0.0.1";
    [Header("Target port number")] public int port = 12345;
    [Header("Send content")] public string hexCode = "FE 04 00 00 00 01 25 C5";
    [Header("Send Button")] public Button Btn_Send;
    private UdpClient udpClient;

    private void Start()
    {<!-- -->
        Btn_Send.onClick.AddListener(OnButtonClick);
    }

    public void OnButtonClick()
    {<!-- -->
        udpClient = new UdpClient(ipAddress, port);
        byte[] data = Encoding.UTF8.GetBytes(hexCode);
        udpClient.Send(data, data.Length);
        
        
    }

    private void OnApplicationQuit()
    {<!-- -->
        udpClient.Close();
    }
}
</code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack.png" alt ="" title="">

Server (receiving end)

using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;

public class UDPSever : MonoBehaviour
{<!-- -->
    private UdpClient udpServer;
    
    [Header("Receive content")] public string Response;
    [Header("Whether to activate the object")] public bool IsActive;
    [Header("Object to be activated")] public GameObject[] OBJ;
    [Header("Server Port")] public int Port = 12345;
    [Header("Do you need activation time")] public bool IsActiveTime;
    [Header("Activation Time")] public float ActiveTime;

    private float ActiveTimeTemp;
    private bool isStart;
    private UnityMainThreadDispatcher mainThreadDispatcher;
    private void Start()
    {<!-- -->
        try
        {<!-- -->
            // Start UDP server
            udpServer = new UdpClient(Port);
            Debug.Log("UDP server has been started, waiting for client connection...");

            mainThreadDispatcher = UnityMainThreadDispatcher.Instance;
            
            //Receive data from the client in a new thread
            IPEndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, Port);
            StartServerReceiver(udpServer, clientEndPoint);
        }
        catch (Exception e)
        {<!-- -->
            Debug.LogError("An error occurred: " + e.Message);
        }
    }

    private void StartServerReceiver(UdpClient server, IPEndPoint clientEndPoint)
    {<!-- -->
        System.Threading.Thread serverThread = new System.Threading.Thread(() =>
        {<!-- -->
            while(true)
            {<!-- -->
                byte[] receivedData = server.Receive(ref clientEndPoint);
                string receivedMessage = Encoding.UTF8.GetString(receivedData);
                
                Client(receivedMessage);

                //Add code here to send response to client
                string responseMessage = "The server has received the message: " + receivedMessage;
                byte[] responseData = Encoding.UTF8.GetBytes(responseMessage);
                server.Send(responseData, responseData.Length, clientEndPoint);
            }
        });

        serverThread.Start();
    }

    public void Client(string received)
    {<!-- -->
        if (received != null)
        {<!-- -->
                    
            //Performance
            Response = received;

            ComparisonResponse(received);
        }

    }

    public void ComparisonResponse(string response)
    {<!-- -->
        switch (response)
        {<!-- -->
            case "FE 04 00 00 00 01 25 C5":
                TimeOnclick();
                break;
        }
    }
    
    
    public void TimeOnclick()
    {<!-- -->
        if(IsActiveTime)
        {<!-- -->
            isStart = true;
            ActiveTimeTemp = ActiveTime;
        }
        else
        {<!-- -->
            ObjActive();
        }
    }

    
    public void ObjActive()
    {<!-- -->
        mainThreadDispatcher.Enqueue(() => {<!-- -->
            foreach (GameObject o in OBJ)
            {<!-- -->
                o.SetActive(IsActive);
            }
        });
    }

    private void OnApplicationQuit()
    {<!-- -->
        udpServer.Close();
    }

    private void Update()
    {<!-- -->
        if(isStart)
        {<!-- -->
            ActiveTimeTemp -= Time.deltaTime;
            if (ActiveTimeTemp <= 0)
            {<!-- -->
                ObjActive();
                isStart = false;
            }
        }
    }
}
</code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack.png" alt ="" title="">

4. Summary

For example, Ctrip, Invoke function, and controlling the visibility of objects must be operated on the main thread, and then when our server monitors the client time, multi-threading is enabled; if the main thread is not used, the operation of controlling the visibility of objects cannot be completed;

Solution: By creating the main thread, the following script can be instantiated and called directly without mounting.

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

public class UnityMainThreadDispatcher : MonoBehaviour
{<!-- -->
    private static readonly Queue<Action> executionQueue = new Queue<Action>();

    private static UnityMainThreadDispatcher _instance = null;

    public static bool Exists
    {<!-- -->
        get {<!-- --> return _instance != null; }
    }

    public static UnityMainThreadDispatcher Instance
    {<!-- -->
        get
        {<!-- -->
            if (!Exists)
            {<!-- -->
                _instance = new GameObject("MainThreadDispatcher").AddComponent<UnityMainThreadDispatcher>();
            }
            return _instance;
        }
    }

    void Update()
    {<!-- -->
        while (executionQueue.Count > 0)
        {<!-- -->
            executionQueue.Dequeue().Invoke();
        }
    }

    public void Enqueue(IEnumerator action)
    {<!-- -->
        executionQueue.Enqueue(() => {<!-- --> StartCoroutine(action); });
    }

    public void Enqueue(Action action)
    {<!-- -->
        executionQueue.Enqueue(action);
    }
}

</code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack.png" alt ="" title="">