[Unity] (Socket) TCP realizes one host in the same LAN to control multiple hosts

A few days ago, the blogger received a task: 5 HTC VIVEPro devices, one of which was for demonstration, and the screens of the other four devices were synchronized.

Before the equipment arrives, the blogger has carried out preliminary preparation work: one host in the same LAN controls multiple hosts

PS: The blogger referred to the articles of other bloggers and found it very useful! ! ! ! ! !

If you need some other TCP operation procedures, please read this blogger's big article, which is very detailed

[Unity] Socket network communication (TCP) - the most basic C# server communication process_unity's tcp to send messages_IM rime's blog-CSDN blog

[Unity] Socket network communication (TCP) - realize simple multi-person chat function_unity socket communication_IM rime's blog-CSDN blog

The following is the specific process of blogger operation, I hope it will be helpful to you

One: The 5 devices are under the same LAN, and the firewalls of all hosts need to be closed, so that each computer can ping each other

1. How to turn off the firewall:

 

 

 2. Ping other people's computers

Win+R to open cmd, ping 192.168.2.5 After pressing the enter key, if the data appears, it means ping

2. To create a server, we need a host as a server (message sender)

1. Open VS and create a console application

 2. Encapsulate the server ServerSocket

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace TCPServer
{
    public class ServerSocket
    {
        private Socket socket;
        private bool isClose;
        private List<ClientSocket> clientList = new List<ClientSocket>();

        public void Start(string ip, int port, int clientNum)
        {
            isClose = false;
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
            socket.Bind(iPEndPoint);
            Console.WriteLine("服务器启动成功...IP:{0},端口:{1}", ip, port);
            Console.WriteLine("开始监听客户端连接...");
            socket.Listen(clientNum);

            ThreadPool.QueueUserWorkItem(AcceptClientConnect);
            ThreadPool.QueueUserWorkItem(ReceiveMsg);
        }

        /// <summary>
        /// 等待客户端连接
        /// </summary>
        /// <param name="obj"></param>
        private void AcceptClientConnect(object obj)
        {
            Console.WriteLine("等待客户端连入..."+ (!isClose));
            while (!isClose)
            {
                Socket clientSocket = socket.Accept();
                ClientSocket client = new ClientSocket(clientSocket, this);
                Console.WriteLine("客户端{0}连入...", clientSocket.RemoteEndPoint.ToString());
                client.SendMsg(Encoding.UTF8.GetBytes("欢迎连入服务端..."));
                clientList.Add(client);
            }
        }

        /// <summary>
        /// 接收消息
        /// </summary>
        /// <param name="obj"></param>
        private void ReceiveMsg(object obj)
        {
            int i;
            while (!isClose)
            {
                if (clientList.Count > 0)
                {
                    for(i = 0; i < clientList.Count; i++)
                    {
                        try
                        {
                            clientList[i].ReceiveClientMsg();
                        }
                        catch(Exception e)
                        {
                            Console.WriteLine(e.Message);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="clientID"></param>
        public void BroadcastMsg(byte[] msg, int clientID)
        {
            if (isClose)
                return;

            for(int i = 0; i < clientList.Count; i++)
            {
                if (clientList[i].clientID != clientID)
                {
                    clientList[i].SendMsg(msg);
                }
            }
        }

        /// <summary>
        /// 释放连接
        /// </summary>
        public void Close()
        {
            isClose = true;
            for(int i = 0; i < clientList.Count; i++)
            {
                clientList[i].Close();
            }

            clientList.Clear();

            socket.Shutdown(SocketShutdown.Both);
            socket.Close();
            socket = null;
        }
    }
}

3. Encapsulate the ClientSocket returned when the client connects

using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace TCPServer
{
    public class ClientSocket
    {
        public static int CLIENT_BEGIN_ID = 1;
        public int clientID;
        public string IP;
        private Socket socket;
        private ServerSocket serverSocket;

        public ClientSocket(Socket clientSocket, ServerSocket serverSocket)
        {
            socket = clientSocket;
            this.serverSocket = serverSocket;
            IP = clientSocket.RemoteEndPoint.ToString();

            clientID = CLIENT_BEGIN_ID;
            ++CLIENT_BEGIN_ID;
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="msg"></param>
        public void SendMsg(byte[] msg)
        {
            if(socket != null)
                socket.Send(msg);
        }

        /// <summary>
        /// 接收消息
        /// </summary>
        public void ReceiveClientMsg()
        {
            if (socket == null)
                return;

            if(socket.Available > 0)
            {
                byte[] msgBytes = new byte[1024*1024];
                int msgLength = socket.Receive(msgBytes);
              
                byte[] tempMsg = new byte[msgLength];
                Buffer.BlockCopy(msgBytes, 0, tempMsg, 0, msgLength);
                serverSocket.BroadcastMsg(tempMsg, clientID);

            }
        }


        /// <summary>
        /// 释放连接
        /// </summary>
        public void Close()
        {
            socket.Shutdown(SocketShutdown.Both);
            socket.Close();
            socket = null;
        }
    }
}

3. The main function is used to read the IP of the configuration file, and pass parameters, (I put the configuration file here on the C drive, because considering the boot-up project, the file format is txt)

using System;
using System.IO;
using System.Text;

namespace TCPServer
{
    class Program
    {
        private static ServerSocket serverSocket;
        static void Main(string[] args)
        {
            string path = @"C:\config.txt"; 
            string IP = "127.0.0.1";
            int PORT = 8080;
            if (File.Exists(path))
            {
                string[] str = File.ReadAllLines(path);
                if (str[0].StartsWith("主设备IP"))
                {
                    IP = str[0].Split('=')[1];
                }
                if (str[1].StartsWith("主设备PORT"))
                {
                    PORT = int.Parse(str[1].Split('=')[1]);
                }
            }
            serverSocket = new ServerSocket();
            serverSocket.Start(IP, PORT, 1024);

            while (true)
            {
                string inputStr = Console.ReadLine();
                if (inputStr == "Quit")
                {
                    serverSocket.Close();
                    break;
                }
                else if (inputStr.Substring(0, 2) == "B:")
                {
                    Console.WriteLine("发送..." + inputStr.Substring(2));
                    serverSocket.BroadcastMsg(Encoding.UTF8.GetBytes(inputStr.Substring(2)), -1);
                }
            }
        }
       
    }
}

4. Package the console.exe to run the program (see this big blog for detailed steps, just follow method 2)

The development and packaging of C# console program as an exe file_c# generates exe_Xiliang's sad blog-CSDN blog

This is my packaged file

3. Start to build five device client Unity running programs

1. Build the UI interface as shown below, and mount the script MainManager.cs on the parent object

Remark:

1. The master controller is both a server and a client;

2. The master controller sends instructions to the other 4 hosts as the sender

3. The other 4 devices are only responsible for receiving instructions

4. You need to copy the above configuration file config.txt and put it in the StreamingAssets folder under the Asset directory (because the client needs to connect to the server, we don’t know the host IP of the donors, so we can only make configuration files)

PS: I made a judgment here in Mainmaneger. If the IP of the host currently running the program is consistent with the IP of the server, then it is the sender; otherwise, it is the receiver.

PS: How to get the IP of the local host

 Go directly to the MainManager code below:

using System;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using UnityEngine;
using UnityEngine.UI;

public class MainManager : MonoBehaviour
{
    public Button sendBtn;
    public InputField inputField;
    public Text NameText;
    public ScrollRect sr;
    private string curDeviceIP = String.Empty;

    void Start()
    {
        sendBtn.onClick.AddListener(SendMsg);
        curDeviceIP = GetLocalIP();
        if (curDeviceIP == NetManager.Instance.IP)
        {
            inputField.gameObject.SetActive(true);
            sendBtn.gameObject.SetActive(true);
            NameText.text = "发送方:" + curDeviceIP;
            NameText.color = Color.red;
        }
        else
        {
            inputField.gameObject.SetActive(false);
            sendBtn.gameObject.SetActive(false);
            NameText.text = "接收方:" + curDeviceIP;
            NameText.color = Color.blue;
        }
        
        NetManager.Instance.ConnectServer();
    }

    // Update is called once per frame
    void Update()
    {
       
    }

    void SendMsg()
    {
        if (inputField.text != "")
        {
            ChatMsg chatMsg = new ChatMsg();
            chatMsg.chatStr = inputField.text;
            NetManager.Instance.Send<ChatMsg>(chatMsg);
            UpdateChatInfo(chatMsg);
            inputField.text = "";
        }
    }
    /// <summary>
    /// 获取本地ip
    /// </summary>
    /// <returns></returns>
    string GetLocalIP()
    {
        NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
        foreach (NetworkInterface adater in adapters)
        {
            if (adater.Supports((NetworkInterfaceComponent.IPv4)))
            {
                UnicastIPAddressInformationCollection uniCast = adater.GetIPProperties().UnicastAddresses;
                if (uniCast.Count > 0)
                {
                    foreach (UnicastIPAddressInformation uni in uniCast)
                    {
                        if (uni.Address.AddressFamily == AddressFamily.InterNetwork)
                        {
                            return uni.Address.ToString();
                        }
                    }
                }
            }
        }

        return "127.0.0.1";
    }
    public void UpdateChatInfo(ChatMsg msgInfo)
    {
        Text chatInfoText = Instantiate(Resources.Load<Text>("UI/MsgInfoText"), sr.content);
        chatInfoText.text = NameText.text + ":" + msgInfo.chatStr;
    }
}

2. Create NetManager.cs to connect to the server, etc.

Here you need to pay attention to the IP and PORT when connecting to the server

 Go directly to the NetManager.cs code

using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
using System;
using System.IO;
using System.Net.NetworkInformation;

public class NetManager : MonoBehaviour
{
    public static NetManager Instance => instance;
    private static NetManager instance;

    private Socket socket;

    private bool isConnect;

    private Queue<byte[]> sendQueue = new Queue<byte[]>();
    private Queue<byte[]> receiveQueue = new Queue<byte[]>();

    private byte[] receiveBytes = new byte[1024 * 1024];

    private MainManager mainManager;

    public string path = String.Empty;
    public string IP = String.Empty;
    public int PORT = 8080;

    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        path = Application.streamingAssetsPath + "/config.txt";
        IP = "127.0.0.1";
        PORT = 8080;
        if (File.Exists(path))
        {
            string[] str = File.ReadAllLines(path);
            if (str[0].StartsWith("主设备IP"))
            {
                IP = str[0].Split('=')[1];
            }
            if (str[1].StartsWith("主设备PORT"))
            {
                PORT = int.Parse(str[1].Split('=')[1]);
            }
        }
    }

    private void Start()
    {
        GameObject chatPanelObj = GameObject.Find("MainManager");
        mainManager = chatPanelObj.GetComponent<MainManager>();
    }

    // Update is called once per frame
    void Update()
    {
        if (receiveQueue.Count > 0)
        {
            ReadingMsgType(receiveQueue.Dequeue());
        }
    }

    /// <summary>
    /// 连接服务器
    /// </summary>
    /// <param name="ip">服务器IP地址</param>
    /// <param name="port">服务器程序端口号</param>
    public void ConnectServer()
    {
        //如果在连接状态,就不执行连接逻辑了
        if (isConnect)
            return;

        //避免重复创建socket
        if (socket == null)
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        //连接服务器
        IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(IP), PORT);

        try
        {
            socket.Connect(ipEndPoint);
        }
        catch (SocketException e)
        {
            print(e.ErrorCode + e.Message);
            return;
        }

        isConnect = true;

        //开启发送消息线程
        ThreadPool.QueueUserWorkItem(SendMsg_Thread);
        //开启接收消息线程
        ThreadPool.QueueUserWorkItem(ReceiveMsg_Thread);
    }

    /// <summary>
    /// 发送消息
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="msg"></param>
    public void Send<T>(T msg) where T : BaseMsg
    {
        //将消息放入到消息队列中
        sendQueue.Enqueue(msg.SerializeData());
    }

    private void SendMsg_Thread(object obj)
    {
        while (isConnect)
        {
            //如果消息队列中有消息,则发送消息
            if (sendQueue.Count > 0)
            {
                socket.Send(sendQueue.Dequeue());
            }
        }
    }

    /// <summary>
    /// 接收消息
    /// </summary>
    /// <param name="obj"></param>
    private void ReceiveMsg_Thread(object obj)
    {
        int msgLength;
        while (isConnect)
        {
            if (socket.Available > 0)
            {
                msgLength = socket.Receive(receiveBytes);
                receiveQueue.Enqueue(receiveBytes);
            }
        }
    }

    private void ReadingMsgType(byte[] msg)
    {
        int msgId = BitConverter.ToInt32(msg, 0);
        switch (msgId)
        {
            case 1001:
                ReadingChatMsg(msg);
                break;
        }
    }

    private void ReadingChatMsg(byte[] msg)
    {
        ChatMsg chatMsg = new ChatMsg();
        chatMsg.ReadingData(msg, 4);
        mainManager.UpdateChatInfo(chatMsg);
    }

    public void Close()
    {
        if (socket != null && isConnect)
        {
            socket.Shutdown(SocketShutdown.Both);
            socket.Close();

            isConnect = false;
        }
    }
   
    private void OnDestroy()
    {
        Close();
    }
}

The above are the two main functions, others can see the source file below

Running sequence: open the server first, and then open the unity running program on each computer in turn.

The following is my final running effect diagram

Source file link: Link: https://pan.baidu.com/s/1pTwGj37ozMlq58OHcIJPIg 
Extraction code: 1234 
--Share from Baidu Netdisk super member V5

https://gitee.com/various-tool-scripts/tcptest.git https://gitee.com/various-tool-scripts/tcptest.git would like to record the blogger's own personal journey with this article, hoping to be helpful to everyone

Guess you like

Origin blog.csdn.net/weixin_39348384/article/details/130842531