Hololens 2模拟器Unity TCP连接问题:Socket连接正常但无数据传输
HoloLens 2模拟器Unity应用与Python脚本TCP连接异常排查
问题现象
Python端socket.connect(server_address)和sock.sendall(message)执行正常,但模拟器端Unity代码卡在using (connectedTcpClient = tcpListener.AcceptTcpClient()),后续断点及打印逻辑均无响应。
已尝试的排查操作
- 在运行模拟器的本机执行Python脚本,将IP改为127.0.0.1/localhost,问题依旧;
- 将脚本中的IP替换为模拟器IP,无法建立连接;
- Unity播放器设置已勾选
InternetClient、InternetClientServer和PrivateNetworkClientServer; - 已按照微软官方指南配置模拟器TCP服务器端口。
代码片段
Python脚本
import socket import sys # Create a TCP/IP socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Connect the socket to the port where the server is listening server_address = ('192.168.1.152', 9090) print('connecting to {} port {}...'.format(*server_address)) sock.connect(server_address) try: # Send data message = b'Hello World!' print('sending {!r}'.format(message)) sock.sendall(message) print('message sent, waiting...') # Look for the response amount_received = 0 amount_expected = len(message) while amount_received < amount_expected: data = sock.recv(16) amount_received += len(data) print('received {!r}'.format(data)) finally: print('closing socket') sock.close()
Unity C#代码
using System; using System.Collections; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using TMPro; using UnityEngine; using UnityEngine.UIElements; public class TCPyManager : MonoBehaviour { #region private members /// <summary> /// TCPListener to listen for incoming TCP connection /// requests. /// </summary> private TcpListener tcpListener; /// <summary> /// Background thread for TcpServer workload. /// </summary> private Thread tcpListenerThread; /// <summary> /// Create handle to connected tcp client. /// </summary> private TcpClient connectedTcpClient; private string clientMessage; private string status; private string data; public TMP_Text statusText; public TMP_Text dataText; #endregion // Use this for initialization void Start() { // Start TcpServer background thread tcpListenerThread = new Thread(new ThreadStart(ListenForIncomingRequests)); tcpListenerThread.IsBackground = true; tcpListenerThread.Start(); } // Update is called once per frame void Update() { statusText.SetText(status); dataText.SetText(data); } /// <summary> /// Runs in background TcpServerThread; Handles incoming TcpClient requests /// </summary> private void ListenForIncomingRequests() { try { // Create listener on raspi IP address port 9090. tcpListener = new TcpListener(IPAddress.Parse("192.168.1.152"), 9090); tcpListener.Start(); data = "Waiting..."; status = "Server is listening"; Byte[] bytes = new Byte[16]; while (true) { status = "Waiting for client"; Thread.Sleep(10); using (connectedTcpClient = tcpListener.AcceptTcpClient()) { status = "Client accepted"; //Get a stream object for reading using (NetworkStream stream = connectedTcpClient.GetStream()) { int length; // Read incoming stream into byte arrary. while ((length = stream.Read(bytes, 0, bytes.Length)) != 0) { clientMessage = System.Text.Encoding.ASCII.GetString(bytes, 0, length); status = "Message received!"; data = clientMessage; SendMessage(clientMessage); } } } } } catch (SocketException socketException) { status = "SocketException " + socketException.ToString(); } } /// <summary> /// Send message to client using socket connection. /// </summary> private void SendMessage(string message) { if (connectedTcpClient == null) { return; } try { // Get a stream object for writing. NetworkStream stream = connectedTcpClient.GetStream(); if (stream.CanWrite) { string serverMessage = message; // Convert string message to byte array. byte[] serverMessageAsByteArray = System.Text.Encoding.ASCII.GetBytes(serverMessage); // Write byte array to socketConnection stream. stream.Write(serverMessageAsByteArray, 0, serverMessageAsByteArray.Length); status = "Server sent message - should be received by client"; } } catch (SocketException socketException) { status = "SocketException " + socketException.ToString(); } } }
排查建议
- 修正Unity端监听IP:不要硬编码固定IP,改用
IPAddress.Any监听所有可用网卡,避免模拟器IP和代码中IP不匹配的问题:tcpListener = new TcpListener(IPAddress.Any, 9090); - 确认模拟器网络映射:HoloLens 2模拟器运行在Hyper-V虚拟机中,需确保宿主机和模拟器网络连通:
- 在模拟器中打开命令提示符,执行
ipconfig获取真实IP; - 在宿主机ping该IP,确认连通性;
- 若ping不通,检查Hyper-V虚拟交换机设置,确保虚拟机和宿主机在同一网络段。
- 在模拟器中打开命令提示符,执行
- 检查防火墙规则:
- 宿主机防火墙需允许Unity应用和Python脚本通过9090端口通信;
- 模拟器内的Windows防火墙需开放9090端口的TCP入站规则。
- 线程安全修正:后台线程修改
status和data时需加锁,避免与主线程的Update函数产生冲突:private readonly object lockObj = new object(); // 后台线程修改状态时 lock(lockObj) { status = "Waiting for client"; } // Update函数读取状态时 lock(lockObj) { statusText.SetText(status); dataText.SetText(data); } - 模拟器内调试:使用Visual Studio远程调试模拟器,查看
Debug.Log输出,确认是否有未捕获的异常;或在模拟器内运行TCP测试工具(如NetCat),验证端口监听是否正常。 - 双向连通性测试:
- 在模拟器中运行TCP服务器,用Python脚本连接,确认基础通信是否正常;
- 在宿主机运行TCP服务器,让Unity应用作为客户端连接,排查是服务器端还是客户端逻辑问题。
内容的提问来源于stack exchange,提问作者issac1222
相关产品推荐
相关产品推荐

