当前位置: 首页> 健康> 知识 > 【Unity/网络】Unity和内网穿透的网络测试 —— 以聊天室为例

【Unity/网络】Unity和内网穿透的网络测试 —— 以聊天室为例

时间:2025/7/17 15:49:31来源:https://blog.csdn.net/Siro_sama/article/details/141196707 浏览次数:0次

这两天在做那个CodeMonky的胡闹厨房的案例,一直困扰我的是关于Lobby和Relay的相关网络服务,需要挂加速器并且延迟不低,所以我一直在寻找一些其他替代方案,想起来之前做一个UEC++的网络枪战时做过一个内网穿透的方法,所以在Unity中也采用这个方案,但中间怎么改IP和端口都没法连接成功,最后就索性单开了一个项目来测试这一块,现在也算是测出来原因了,这里写个笔记记录下过程

左客户端,右主机端

文章目录

    • 案例概述
    • 关键代码部分
      • MessageManager
      • MessageUI
      • SendUI
    • 远程连接

案例概述

首先先说一下写的聊天室案例

使用MessageManager来作为RPC调用,提供全局添加Message方法的单例,其他类可以订阅对应的委托进行自己的处理,比如UI部分可以根据委托创建消息显示

NetworkManager是Unity提供的网络类,配合UnityTransport实现网络的传输和连接的管理

UI部分分三大部分:

  • 第一部分是输入消息内容并发送的部分
  • 第二部分是提供启动Host和Client的按钮部分
  • 第三部分就是消息的生成显示的部分。

关键代码部分

MessageManager

添加消息的RPC部分,该部分只负责转发委托,并不实际存储消息内容,由于一开始是希望方便测试查看网络相关的回调信息,所以添加了一个LogLevel控制消息的颜色,但后来又想不如加个聊天,再后来就成了个聊天室了()

    public void AddMessage(string name, string content, LogLevel level = LogLevel.Normal){AddMessageServerRPC(name, content, level);}[ServerRpc(RequireOwnership = false)]private void AddMessageServerRPC(string name, string content, LogLevel level = LogLevel.Normal){AddMessageClientRPC(name, content, level);}[ClientRpc]private void AddMessageClientRPC(string name, string content, LogLevel level = LogLevel.Normal){onMessageReceived.Invoke(name, content, level);}

接下来是在该类中重新在NetworkManager的StartHost和StartClient外面裹一层自己的代码

public void StartHost()
{//这一句后面详细解释NetworkManager.Singleton.GetComponent<UnityTransport>().SetConnectionData("你的公网IP", 7777, "0.0.0.0");//提示打印玩家的连接通知//Namer.GM是一个名称类,拿来代替直接使用"GM"的字符串方式,方便统一名称,统一修改,查找引用等NetworkManager.Singleton.OnClientConnectedCallback += (clientId) =>{Instance.AddMessage(Namer.GM, "player " + clientId + " Connected.", LogLevel.Warning);clientIDList.Add(clientId);};NetworkManager.Singleton.StartHost();
}public void StartClient()
{NetworkManager.Singleton.OnClientDisconnectCallback += (clientId) =>{onMessageReceived.Invoke(Namer.GM, "未能成功连接到服务器!", LogLevel.Error);};NetworkManager.Singleton.StartClient();
}

最后是该类中向外部提供的委托

public UnityAction<string, string, LogLevel> onMessageReceived;

MessageUI

接下来是消息的显示部分,这一部分订阅单例的消息委托并显示出来,注意textPrefab是一个网络物体,其父级要在初始化时就提供。并且要在NetworkManager的NetworkPrefabList中添加该Prefab

public class MessageUI : MonoBehaviour
{[SerializeField] private TextBlockUI textPrefab;[SerializeField] private Transform textParent;private void Start(){MessageManager.Instance.onMessageReceived += (name, content, level) =>{TextBlockUI obj = Instantiate(textPrefab, textParent);obj.SetText(name, content, level);};}
}

SendUI

这一部分算是负责发送消息的部分,本质上就是获取消息然后调用写好的函数就行,另外连接Host和Client只需要两个按钮分别调用MessageManager中对应的StartHost和StartClient就行,之后就不写了

public class SendUI : MonoBehaviour
{[SerializeField] private TMP_InputField inputField;[SerializeField] private TMP_Dropdown dropdown;[SerializeField] private Button submitBtn;[SerializeField] private TMP_InputField nameField;// Start is called before the first frame updatevoid Start(){submitBtn.onClick.AddListener(() =>{string name = nameField.text;string content = inputField.text;LogLevel level = (LogLevel)dropdown.value;MessageManager.Instance.AddMessage(name, content, level);inputField.text = "";});nameField.onEndEdit.AddListener((str) =>{PlayerPrefs.SetString("PlayerName", str);});}
}

上述写完后,在本地进行测试,没问题的话就可以准备进行远程连接了

远程连接

远程连接有许多方案,这里说一下我知道的

  1. Lobby + Relay : 在国内无服务器,连接靠玄学

  2. Unity Online Services:国内的网络服务,相关教程和API可在官网找到,可用,但是免费用户只有五十次房间额度,用完就无了

  3. 内网穿透:直接连接到玩家主机上,花费视使用的软件而定,最经济的办法是内网穿透做服务器然后放云上,或者像我一样直接用来Host连接,不额外搞服务器

内网穿透:

我使用的是路由侠,穿透时都会分配到一个公网的域名和对应端口,其映射到的内网端口通常选为127.0.0.1 : 7777,IP输入本机IP,后面的7777端口只要选一个没其他进程用的即可

确保穿透是打开的,域名对应的IP可以直接在CMD窗口中输入“ping 公网域名”,即可得到IP地址

公网的IP地址和端口填入Unity中NetworkManager下的UnityTransport的Address和Port中,并且打开运行远程连接

到达这一步会发现哪里都正常,但是客户端就是连不上服务器,最主要的一点是监听的端口问题

先打开服务器,再使用CMD,输入netstat -an | find "端口号"可以得到当前端口的状态,一般是

UDP 0.0.0.0:28907 *:*,这说明该端口当前监听所有UDP协议的IP地址连接,主机是正常监听的,

客户端也是连接的公网IP和端口,那么唯一的可能就是主机监听的端口和客户端不一致,客户端使用公网IP和端口进行连接,但最后端口会被映射到内网端口上,因此主机应当监听的是内网的对应端口,所以在StartHost时需要修改监听的端口值,也就是MessageManager中StartHost中的第一段代码

    NetworkManager.Singleton.GetComponent<UnityTransport>().SetConnectionData("你的公网IP", 7777, "0.0.0.0");

自此大功告成,能够通过内网穿透进行通信。

关键字:【Unity/网络】Unity和内网穿透的网络测试 —— 以聊天室为例

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: