【Unity】(Socket)TCP 实现同一局域网 一台主机控制多台主机

这篇具有很好参考价值的文章主要介绍了【Unity】(Socket)TCP 实现同一局域网 一台主机控制多台主机。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前几天博主接到一个任务:5台HTCVIVEPro设备,其中一台设备进行演示,另外四台设备画面同步。

在设备没到之前,博主进行了一下前期准本工作:同一局域网 一台主机控制多台主机

PS:博主参考了其它博主大大的文章,感觉很有用!!!!!!

如果需要其它的一些TCP操作流程,请看这个博主大大的文章,很详细

【Unity】Socket网络通信(TCP) - 最基础的C#服务端通信流程_unity的tcp发送消息_IM雾凇的博客-CSDN博客

【Unity】Socket网络通信(TCP) - 实现简单的多人聊天功能_unity socket通信_IM雾凇的博客-CSDN博客

以下开始了博主操作的具体流程,希望对你有所帮助

一:5台设备同一局域网下,且所有主机的防火墙需要关闭,要保证每台电脑都能互相ping通

1.如何关闭防火墙:unity tcp,tcp/ip,unity,c#

 unity tcp,tcp/ip,unity,c#

 unity tcp,tcp/ip,unity,c#

 2.ping他人电脑

win+R打开cmd,    ping 192.168.2.5    按下enter键之后,出现数据即为ping通unity tcp,tcp/ip,unity,c#

二.创建服务器,我们需要一台主机作为服务器(消息发送方)

1.打开VS,创建控制台应用程序unity tcp,tcp/ip,unity,c#

 2.封装服务端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.封装客户端连入时返回的ClientSocket

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.主函数,用来读取配置文件的IP,以及传参,(配置文件我在这里放到了C盘,因为考虑到开机自启的项目,文件格式txt的)unity tcp,tcp/ip,unity,c#unity tcp,tcp/ip,unity,c#

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.打包控制台.exe运行程序(详细步骤请看这位大大的博客,按照方法二即可)

C# 控制台程序的开发和打包为一个exe文件_c# 生成exe_西凉的悲伤的博客-CSDN博客

这是我打包之后的文件unity tcp,tcp/ip,unity,c#

三,开始搭建五台设备客户端Unity运行程序

1.搭建如下图UI界面,并在父物体上挂载脚本MainManager.csunity tcp,tcp/ip,unity,c#

备注:

1.主控制机既是服务器又是客户端;

2.主控制机作为发送方发送指令到另外4台主机上

3.另外4台设备只负责接收指令即可

4.需要把上述配置文件config.txt复制一份放在Asset目录下的StreamingAssets文件夹里(因为客户端需要连接服务器,金主爸爸们的主机IP我们也不晓得,只能做配置文件啦)

PS:在Mainmaneger这里我做了一个判断,若当前运行程序的主机IP与服务器IP一致,那么即为发送方;反之即为接收方unity tcp,tcp/ip,unity,c#

PS:如何获取本地主机的IPunity tcp,tcp/ip,unity,c#

 下面直接上MainManager代码:

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.创建NetManager.cs用来连接服务器等

在这里需注意连接服务器时的IP和PORTunity tcp,tcp/ip,unity,c#

 直接上NetManager.cs代码

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

以上是两个主要的函数,其它的可自行看下方源文件

运行顺序:先打开服务器,在每台电脑上依次打开unity运行程序即可。

下面是我最终的运行效果图unity tcp,tcp/ip,unity,c#

源文件链接:链接:https://pan.baidu.com/s/1pTwGj37ozMlq58OHcIJPIg 
提取码:1234 
--来自百度网盘超级会员V5的分享

https://gitee.com/various-tool-scripts/tcptest.githttps://gitee.com/various-tool-scripts/tcptest.git谨以此文记录博主自己的个人历程,希望对大家有所帮助文章来源地址https://www.toymoban.com/news/detail-686730.html

到了这里,关于【Unity】(Socket)TCP 实现同一局域网 一台主机控制多台主机的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 如何判断2台设备是否在同一个局域网?

    需要局域网环境debug,但是家里只有一个无线路由器+台式机(有线连接路由器)+开发板(无线连接到路由器),因此好奇台式机和开发板是否是同一局域网? 1.台式机输入ipconfig,获取网络信息。   ip 地址是:192.168.10.2 子网掩码是:255.255.255.0 2.开发板因为是linux 环境,shell 下

    2024年02月11日
    浏览(72)
  • Ubuntu下扫描同一局域网的其他设备IP

    1.安装arp-scan 2.使用ifconfig查看本机IP地址,一般有线在interface en0/eth0, 无线在wlan0上 箭头中所指是我虚拟机的IP地址 3.查看同一局域网的其他设备IP 注意: \\\"wlo1 要换成自己的网口名\\\" 箭头所指就是我宿主机的IP地址了。

    2024年02月12日
    浏览(63)
  • 判断两个 IP 地址是否在同一个局域网中

    如何判断两个 IP 地址是否在同一个局域网中, 核心知识点是出于一个网络号, 主要是通过本身ip 与 所处的子网掩码进行 计算处理是否处于同一个局域网中(在 TCP/IP协议规则里面,IP地址与子网掩码做与运算)。

    2024年02月13日
    浏览(75)
  • Unity + Mirror实现卡牌游戏局域网联机

    局域网联机插件 Mirror:Mirror | 网络 | Unity Asset Store 本地客户端测试多人游戏(不用打包)插件 : ParrelSync Mirror官方文档:General - Mirror (gitbook.io) 导入Mirror Package 创建空物体,添加 Network Manager , Network Manager HUD 以及 KCP Transport (也可以选择其他网络连接方式) 导入 ParrelSyn

    2024年01月23日
    浏览(50)
  • Python语言实现两台计算机用TCP协议跨局域网通信

    (这张图是在我本地电脑上用pycharm运行两个程序测试,实际可以在两台电脑上分别运行。) 实现的功能: 跨局域网通信(仅支持两台计算机) 跨局域网收发小文件,支持缓存在服务器,再一键接收(仅支持两台计算机) 在服务器上运行server.py程序,在两台客户机上分别运行

    2024年02月04日
    浏览(53)
  • 利用FFmpeg实现windows和linux(federo系统)在局域网环境中的usb摄像头RTSP推流与拉流(在同一局域网下任意PC设备都可以进行拉流操作)

    FFmpeg 是一个免费、开源的跨平台视频和音频流处理工具。 首先,打开终端(在 Windows 中是命令提示符,在 Windows 搜索栏中输入“cmd”,然后打开命令提示符),然后运行以下命令以检查您的系统上是否已安装 FFmpeg: 转到 FFmpeg 官方网站,然后下载最新版本的 Windows 安装包。

    2024年02月02日
    浏览(50)
  • Unity 基于Netcode for gameObjects实现局域网同步

    1.需要将unity升级到2021.3及以后的版本的稳定版本,使用不稳定的2022版本测试过,存在打包问题: 1. Netcode for gameObjects 2. Multiplayer Tools 该package是附带Netcode for GameObjects手动安装的 3. Burst 该Package同样也是附带安装,如果在不稳定的2022版本中打包问题也源于这个package,猜测可能

    2024年02月11日
    浏览(43)
  • ipad作为扩展屏的最简单方式(仅需在同一局域网下,无需数据线)

    ipad和win都下载安装toDesk,并且都处于同一局域网下 连接ipad,在ipad中输入win设备的设备密码和临时密码,连接上后可以看到ipad会是win屏幕的镜像 在win上的toDesk的设备列表的ipad右侧选择扩展屏模式,win+p,选择扩展选项,可以看到ipad成为了一个默认win桌面的扩展屏 我这里是

    2024年02月21日
    浏览(186)
  • 在局域网中的另一台主机如何访问WSL中的MiniKube生成的微服务

    我在WSL(Windows Subsystem for Linux)安装了Minikube中并设置好了Kubernetes环境。在Kubernetes环境中配置好微服务后,从局域网中的另一台主机无法访问WSL中的MiniKube生成的微服务,通过网络转发解决了这个问题。 设置Minikube可参考How to Install Minikube on Ubuntu 22.04 / 20.04,验证在WSL(Wind

    2024年02月12日
    浏览(54)
  • 同一局域网内IP 192.168.1.10 和 IP 10.10.10.8 可以互相访问吗?

    同一局域网内IP 192.168.1.10 和 IP 10.10.10.8 可以互相访问吗? 1、网上邻居的方式: 鼠标点击 我的电脑 属性 计算机名,查看一下 计算机名(这个可以点击更改,自己设定和更改) 查看一下工作组,一般默认都是 workgroup 如果两个电脑都设置同一工作组,没有其他安全限制的情

    2024年02月12日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包