(2025)Unity局域网多客户端Socket通信

前言

在开发一些展览馆项目时需要Pad通过局域网控制馆内各个设备的状态,但展览馆又不允许连接外网,故需要局域网多客户端Socket通信。

服务端代码如下

using System.Net.Sockets;
using System.Net;
using System.Text;
using Newtonsoft.Json;

public static class SocketServer
{
    public static Socket serverSocket;
    public static List<Socket> clientSockets = new List<Socket>();
    public static async Task Init()
    {
        int port = 10000;
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPAddress ipAddress = IPAddress.Any;
        IPEndPoint endPoint = new IPEndPoint(ipAddress, port);
        serverSocket.Bind(endPoint);
        serverSocket.Listen(10);

        Console.WriteLine("服务器正在监听端口 {0}...", port);

        while (true)
        {
            // 异步等待并接受客户端连接
            Socket clientSocket = await Task.Run(() => serverSocket.Accept());

            Console.WriteLine("客户端已连接");
            clientSockets.Add(clientSocket);

            // 为每个客户端启动一个异步任务来接收消息
            _ = Task.Run(() => ReceiveMessage(clientSocket)); // 异步接收消息,不阻塞主线程
        }
    }
}  

服务端不实现任何业务,故用Console程序,提高稳定性。此代码同样适用于Unity,无需改动。

接收消息方法代码如下

public static async Task ReceiveMessage(Socket clientSocket)
    {
        byte[] buffer = new byte[1024];
        while (true)
        {
            int a = clientSocket.Receive(buffer);
            if (a > 0)
            {
                string serverResponse = Encoding.UTF8.GetString(buffer, 0, a);
                
                Console.WriteLine("serverResponse ");

            }
        }
    }
    

发送消息方法代码如下 

public static int SendMessage(Socket clientSocket, string data)
    {
        return clientSocket.Send(Encoding.UTF8.GetBytes(data));
    }
 clientSockets列表中包含所有连接进来的客户端,在客户端连接成功后向服务端发送自己的ID,可以随后在服务端把ID和Socket存成字典方便访问。

Unity客户端代码如下 

public static class Client
{
    public static Socket clientSocket;

    // 连接到服务器并进行通信
    public static async Task ConnectToServerAsync()
    {
        // 服务器地址和端口
        string serverIP = "127.0.0.1";
        int port = 10000;

        // 创建 TCP 套接字,连接服务器
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(serverIP), port);

        try
        {
            // 异步连接到服务器
            await Task.Factory.StartNew(() => clientSocket.Connect(endPoint));

            Debug.Log("已连接到服务器");
            SendMessage("client已连接,ID: 3278947238947923847");
            // 在这里添加一个循环,以便不断与服务器进行通信
            // 注意:这个连接将会保持打开状态,直到你手动断开连接
            ReceiveMessage();
            
        }
        catch (Exception ex)
        {
            Debug.LogError("连接失败: " + ex.Message);
        }
    }
    public static async Task SendMessage(string message)
    {
        byte[] messageBytes = Encoding.UTF8.GetBytes(message);
        await Task.Run(() => clientSocket.Send(messageBytes));
        Debug.Log(message);
        
    }
    public static async Task ReceiveMessage()
    {
        byte[] buffer = new byte[1024];
        int bytesRead;
        string serverResponse;
        while (true)
        {
            // 异步接收服务器的响应
            bytesRead = await Task.Factory.StartNew(() => clientSocket.Receive(buffer));
            serverResponse = Encoding.UTF8.GetString(buffer, 0, bytesRead);
            if (!string.IsNullOrEmpty(serverResponse))
            {
                Debug.Log("收到服务器消息: " + serverResponse);             
            }
        }
    }
    // 关闭连接的方法
    public static void CloseConnection()
    {
        if (clientSocket != null && clientSocket.Connected)
        {
            clientSocket.Close();
            Debug.Log("连接已关闭");
        }
    }
}

客户端连接效果如下