[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 protocols TCP, UDP
The server has many repeated methods, which is interesting You can write it as a base class to reduce the repetition rate

I. Introduction

Realize sending specified commands through TCP or UDP protocols, and the receiving end performs operations related to activation of control objects;
Pay attention to the summary at the end;
Demo Download

2. TCP protocol

Client (sender)

public class TCPSender : MonoBehaviour
{
    
    
    [Header("目标IP地址")] public string ipAddress = "127.0.0.1"; 
    [Header("目标端口号")] public int port = 12345; 
    [Header("发送内容")] public string hexCode = "FE 04 00 00 00 01 25 C5"; 
    [Header("发送按钮")] 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();
    }
}

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("接收内容")] public string Response;
    [Header("是否激活对象")] public bool IsActive;
    [Header("待激活对象")] public GameObject[] OBJ;
    [Header("服务器端口")] public int Port = 12345;
    [Header("是否需要激活时间")] public bool IsActiveTime;
    [Header("激活时间")] public float ActiveTime;

    private float ActiveTimeTemp;
    private bool isStart;
    private UnityMainThreadDispatcher mainThreadDispatcher;
    private void Start()
    {
    
    
        try
        {
    
    
            // 创建TCP监听器
            tcpListener = new TcpListener(IPAddress.Any, Port);
            tcpListener.Start();
            Debug.Log("TCP服务器已启动,等待客户端连接...");

            //开启主线程
            mainThreadDispatcher = UnityMainThreadDispatcher.Instance;
           
            // 在新线程中等待客户端连接
            System.Threading.Thread acceptThread = new System.Threading.Thread(AcceptClients);
            acceptThread.Start();
        }
        catch (Exception e)
        {
    
    
            Debug.LogError("发生错误: " + e.Message);
        }
    }

    private void AcceptClients()
    {
    
    
        while (true)
        {
    
    
            // 等待客户端连接
            TcpClient client = tcpListener.AcceptTcpClient();
            Debug.Log("客户端已连接: " + ((IPEndPoint)client.Client.RemoteEndPoint).Address);

            // 在新线程中处理客户端请求
            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)
            {
    
    
                // 处理客户端发送的数据
                string data = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                Debug.Log("接收到消息: " + data);
                
                //处理消息
                Client(data);

                // 可以在这里回复客户端
                string response = "服务器已接收消息: " + data;
                byte[] responseBytes = Encoding.UTF8.GetBytes(response);
                stream.Write(responseBytes, 0, responseBytes.Length);
            }

            client.Close();
        }
        catch (Exception e)
        {
    
    
            Debug.LogError("处理客户端请求时发生错误: " + e.Message);
        }
    }

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

    public void Client(string received)
    {
    
    
        if (received != null)
        {
    
    
            //表现
            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 Update()
    {
    
    
        if (isStart)
        {
    
    
            ActiveTimeTemp -= Time.deltaTime;
            if (ActiveTimeTemp <= 0)
            {
    
    
                ObjActive();
                isStart = false;
            }
        }
    }
}

3. UDP protocol

Client (sender)

public class UdpSender : MonoBehaviour
{
    
    
    [Header("目标IP地址")] public string ipAddress = "127.0.0.1"; 
    [Header("目标端口号")] public int port = 12345; 
    [Header("发送内容")] public string hexCode = "FE 04 00 00 00 01 25 C5"; 
    [Header("发送按钮")] 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();
    }
}

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("接收内容")] public string Response;
    [Header("是否激活对象")] public bool IsActive;
    [Header("待激活对象")] public GameObject[] OBJ;
    [Header("服务器端口")] public int Port = 12345;
    [Header("是否需要激活时间")] public bool IsActiveTime;
    [Header("激活时间")] public float ActiveTime;

    private float ActiveTimeTemp;
    private bool isStart;
    private UnityMainThreadDispatcher mainThreadDispatcher;
    private void Start()
    {
    
    
        try
        {
    
    
            // 启动UDP服务器
            udpServer = new UdpClient(Port);
            Debug.Log("UDP服务器已启动,等待客户端连接...");

            mainThreadDispatcher = UnityMainThreadDispatcher.Instance;
            
            // 在新线程中接收来自客户端的数据
            IPEndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, Port);
            StartServerReceiver(udpServer, clientEndPoint);
        }
        catch (Exception e)
        {
    
    
            Debug.LogError("发生错误: " + 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);

                // 在这里添加向客户端发送响应的代码
                string responseMessage = "服务器已收到消息: " + receivedMessage;
                byte[] responseData = Encoding.UTF8.GetBytes(responseMessage);
                server.Send(responseData, responseData.Length, clientEndPoint);
            }
        });

        serverThread.Start();
    }

    public void Client(string received)
    {
    
    
        if (received != null)
        {
    
    
                    
            //表现
            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;
            }
        }
    }
}

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);
    }
}

Guess you like

Origin blog.csdn.net/Xz616/article/details/134217385