Unity TCP客户端Windows正常运行、安卓端(同Wi-Fi网络)无法与服务器通信的问题排查
我来帮你一步步拆解这个问题,同Wi-Fi下跨设备的TCP连接踩过的坑还真不少,结合你的代码和场景,咱们从最可能的原因开始排查:
1. 客户端代码的致命错误:手机上连的是自己的IP!
看你的Unity客户端代码,这段逻辑在Windows上能跑纯属巧合:
string hostName = Dns.GetHostName(); IPHostEntry ipHostEntry = Dns.GetHostEntry(hostName); IPAddress ipAddress = ipHostEntry.AddressList[1];
- 在Windows上运行Unity时,
Dns.GetHostName()获取的是你电脑的主机名,解析后拿到的是电脑的IP,刚好和服务器在同一设备/同网段,所以能连上。 - 但在手机上运行时,
Dns.GetHostName()获取的是手机自己的主机名,解析出来的是手机本地的IP(比如192.168.1.105),你让手机连自己的7777端口,当然找不到你的服务器啊!
解决方法:
把客户端代码里的IP地址改成你电脑的内网IPv4地址(不是127.0.0.1,是同Wi-Fi下的内网IP,比如192.168.1.100这种)。比如:
// 直接替换成你的电脑内网IPv4,先手动写死测试 IPAddress ipAddress = IPAddress.Parse("192.168.1.100"); IPEndPoint endPoint = new IPEndPoint(ipAddress, 7777);
怎么查电脑的内网IP?Windows按Win+R输cmd,然后敲ipconfig,找Wi-Fi模块下的“IPv4地址”就是。
2. 服务器绑定的IP地址不稳定,可能没监听Wi-Fi网卡
你的服务器代码里用了ipHostEntry.AddressList[1],这个列表的顺序是完全不固定的!有时候它是IPv4,有时候是IPv6,有时候是有线网卡的IP,有时候是Wi-Fi的。如果服务器绑定到了有线网卡的IP或者本地回环(127.0.0.1),手机当然连不上。
解决方法:
要么绑定到0.0.0.0(表示监听所有可用网卡的IPv4地址,不管是有线还是Wi-Fi),要么明确获取你的Wi-Fi内网IPv4:
// 方法1:绑定0.0.0.0,最简单可靠 IPAddress ipAddress = IPAddress.Any; // 等价于0.0.0.0 IPEndPoint endPoint = new IPEndPoint(ipAddress, 7777);
或者方法2:遍历AddressList找对应的内网IPv4:
IPAddress ipAddress = null; foreach (var addr in Dns.GetHostEntry(Dns.GetHostName()).AddressList) { // 找IPv4且不是回环地址的 if (addr.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(addr)) { ipAddress = addr; break; } } if (ipAddress == null) { Console.WriteLine("找不到可用的IPv4地址!"); return; } IPEndPoint endPoint = new IPEndPoint(ipAddress, 7777);
3. Windows防火墙拦截了外部连接请求
这是跨设备连接最容易忽略的点:你在VS里运行的服务器程序,Windows防火墙大概率没允许它接收来自其他设备的连接,手机的请求直接被防火墙挡了。
解决方法:
- 临时测试:打开Windows Defender防火墙,暂时关闭(不推荐长期关闭,测试完立刻打开),然后再用手机连一次,如果能连上,就说明是防火墙的问题。
- 永久解决:添加防火墙入站规则:
- 按Win+S搜“Windows Defender防火墙高级设置”
- 左侧点“入站规则”,右侧点“新建规则”
- 规则类型选“端口”,下一步
- 选“TCP”,特定本地端口填
7777,下一步 - 选“允许连接”,下一步
- 勾选“域”、“专用”(家用Wi-Fi属于专用网络),下一步
- 给规则起个名字比如“MMORPG Server 7777”,完成。
4. 安卓客户端缺少网络权限
Unity打包安卓时,如果没开启网络权限,应用连不上网络。虽然新版本Unity默认会加,但保险起见确认一下:
- 打开Unity的
Edit > Project Settings > Player - 切换到Android平台,找到
Other Settings里的Permissions - 确保
Internet权限是勾选状态;如果没找到,手动添加到Plugins/Android文件夹下的AndroidManifest.xml:<uses-permission android:name="android.permission.INTERNET" />
5. 安卓主线程阻塞导致连接失败
你的客户端代码是在Start()里同步执行Connect()、Send()、Receive(),安卓对主线程的阻塞非常敏感,超过几秒就会触发ANR(应用无响应),甚至直接被系统终止操作,导致连接还没建立就失败了。
解决方法:
把网络操作放到子线程里,比如:
void Start() { // 开子线程处理网络 Thread netThread = new Thread(ConnectToServer); netThread.IsBackground = true; netThread.Start(); } void ConnectToServer() { try { IPAddress ipAddress = IPAddress.Parse("192.168.1.100"); // 替换成你的服务器IP IPEndPoint endPoint = new IPEndPoint(ipAddress, 7777); Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); socket.Connect(endPoint); byte[] send = Encoding.UTF8.GetBytes("Hello From Unity"); socket.Send(send); byte[] recv = new byte[1024]; int len = socket.Receive(recv); string recvData = Encoding.UTF8.GetString(recv, 0, len); // 注意:Unity的Debug.Log必须在主线程调用,用Invoke切回去 InvokeOnMainThread(() => Debug.Log(recvData)); socket.Close(); } catch (Exception e) { InvokeOnMainThread(() => Debug.LogError("连接失败:" + e.Message)); } } // 简单的主线程调度方法 void InvokeOnMainThread(Action action) { if (action == null) return; lock (_mainThreadActions) { _mainThreadActions.Add(action); } } private readonly List<Action> _mainThreadActions = new List<Action>(); void Update() { lock (_mainThreadActions) { foreach (var action in _mainThreadActions) { action.Invoke(); } _mainThreadActions.Clear(); } }
这段代码里加了一个简单的主线程调度逻辑,确保Debug.Log这类Unity API在主线程执行,避免报错。
最后,测试步骤建议
- 先修改服务器代码,绑定0.0.0.0,启动服务器,看控制台输出的监听信息是否为
0.0.0.0:7777。 - 查电脑的内网IPv4,修改Unity客户端代码,直接用这个IP,并且把网络操作放到子线程。
- 给Windows防火墙添加7777端口的入站规则。
- 打包安卓APK,安装到手机,确保手机和电脑在同一Wi-Fi下,运行APK,看服务器控制台有没有收到连接请求。
如果还是不行,你可以在手机端的异常捕获里把错误信息打出来(比如连接超时、拒绝连接等),这样能更精准定位问题~




