Unity中通过代理连接ClientWebSocket失败问题(安卓与iOS)
Unity中ClientWebSocket通过代理连接失败的排查与解决
问题描述
我正尝试在Unity中通过代理配置使用ClientWebSocket连接WebSocket服务器,代码如下:
var source = new CancellationTokenSource(); var token = source.Token; var socket = new ClientWebSocket(); WebRequest.DefaultWebProxy = new WebProxy(proxyUrl, false); // 尝试设置DefaultWebProxy也没用 socket.Options.Proxy = new WebProxy(proxyUrl, false); await socket.ConnectAsync(uri, token);
运行时抛出Unable to connect to the remote server错误,堆栈跟踪如下:
11-10 14:16:41.013 I/Unity (12692): !!! System.Net.WebSockets.WebSocketException (0x80004005): Unable to connect to the remote server ---> System.Net.Sockets.SocketException (0x80004005): mono-io-layer-error (111) 11-10 14:16:41.013 I/Unity (12692): at System.Net.Sockets.SocketAsyncResult.CheckIfThrowDelayedException () [0x00000] in <00000000000000000000000000000000>:0 11-10 14:16:41.013 I/Unity (12692): at System.Net.Sockets.Socket.EndConnect (System.IAsyncResult asyncResult) [0x00000] in <00000000000000000000000000000000>:0 11-10 14:16:41.013 I/Unity (12692): at System.Net.Sockets.Socket+<>c.<ConnectAsync>b__10_0 (System.IAsyncResult iar) [0x00000] in <00000000000000000000000000000000>:0 11-10 14:16:41.013 I/Unity (12692): at System.Net.Sockets.SocketAsyncResult+<>c.<Complete>b__27_0 (System.Object state) [0x00000] in <00000000000000000000000000000000>:0 11-10 14:16:41.013 I/Unity (12692): at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () [0x00000] in <00000000000000000000000000000000>:0 11-10 14:16:41.013 I/Unity (12692): at System.Threading.ThreadPoolWorkQueue.Dispatch () [0x00000] in <00000000000000000000000000000000>:0 11-10 14:16:41.013 I/Unity (12692): at System.Threading._ThreadPoolWaitCallback.PerformWaitCallb
另外,使用HttpWebRequest配置相同代理能成功发起请求:
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; WebRequest.DefaultWebProxy = new WebProxy(proxyUrl, false); request.Proxy = new WebProxy(proxyUrl, false); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); response.Close();
尝试自定义实现IWebProxy接口,但GetProxy和IsBypassed方法从未被调用:
public class WebSocketProxy : IWebProxy { private ICredentials iCredentials; private Uri webProxyUri; public WebSocketProxy(Uri proxyUri) { webProxyUri = proxyUri; } public ICredentials Credentials { get { return iCredentials; } set { if (iCredentials != value) { iCredentials = value; } } } public Uri? GetProxy(Uri destUri) { // Always use the same proxy. Debug.Log("GetProxy called"); return webProxyUri; } public bool IsBypassed(Uri hostUri) { // Never bypass the proxy. Debug.Log("IsBypassed called"); return false; } }
可能的原因与解决方法
1. ClientWebSocket仅支持SOCKS代理(不支持HTTP代理)
Unity使用的Mono版本中,ClientWebSocket的Proxy配置仅对SOCKS代理生效。HTTP代理能在HttpWebRequest中工作,是因为HTTP请求本身支持通过代理转发,但WebSocket需要先建立TCP隧道,默认的ClientWebSocket不会自动处理HTTP代理的隧道逻辑,导致连接被拒绝(错误码111即连接被拒绝)。
解决方法:手动实现HTTP代理隧道
先向代理发送CONNECT请求建立TCP隧道,再在隧道上进行WebSocket握手:
// 1. 与代理建立TCP连接 var proxyUri = new Uri(proxyUrl); var proxyTcpClient = new TcpClient(); await proxyTcpClient.ConnectAsync(proxyUri.Host, proxyUri.Port); // 2. 发送CONNECT请求创建隧道 var connectRequest = $"CONNECT {uri.Host}:{uri.Port} HTTP/1.1\r\nHost: {uri.Host}:{uri.Port}\r\n\r\n"; var requestBuffer = Encoding.ASCII.GetBytes(connectRequest); await proxyTcpClient.GetStream().WriteAsync(requestBuffer, 0, requestBuffer.Length); // 3. 验证代理响应,确认隧道建立成功 var responseBuffer = new byte[1024]; var readLength = await proxyTcpClient.GetStream().ReadAsync(responseBuffer, 0, responseBuffer.Length); var proxyResponse = Encoding.ASCII.GetString(responseBuffer, 0, readLength); if (!proxyResponse.StartsWith("HTTP/1.1 200")) { throw new Exception("代理隧道建立失败"); } // 4. 使用已建立的隧道连接WebSocket服务器 var socket = new ClientWebSocket(); await socket.ConnectAsync(uri, CancellationToken.None, proxyTcpClient.GetStream());
2. 代理地址解析异常
即使HttpWebRequest能正常解析proxyUrl,ClientWebSocket的代理解析逻辑可能存在差异,比如URL格式不兼容。
解决方法:手动拆分代理主机和端口
var proxyUri = new Uri(proxyUrl); var proxy = new WebProxy(proxyUri.Host, proxyUri.Port); socket.Options.Proxy = proxy;
3. 移动端网络权限缺失
从日志看是Android环境,需确保应用具备网络访问权限:
- 检查Unity
PlayerSettings > Android > Other Settings > Internet Access设置为Require; - 确认AndroidManifest.xml中包含
<uses-permission android:name="android.permission.INTERNET" />权限。
4. 自定义IWebProxy未生效的原因
Unity的ClientWebSocket底层未实现IWebProxy的调用逻辑,仅依赖系统代理或特定类型的代理配置,因此自定义的IWebProxy方法不会被触发,无需继续尝试该方案。
内容的提问来源于stack exchange,提问作者Robert-96
相关产品推荐
相关产品推荐

