SteamNetworkingSockets无法建立连接问题排查(C#、Steamworks.NET、MonoGame)
当前实现与问题场景
我用C#、Steamworks.NET和MonoGame开发时,遇到SteamNetworkingSockets无法建立连接的问题,具体实现如下:
- 两台设备每帧(60fps锁定)调用回调:
public void Update() { SteamAPI.RunCallbacks(); }
- 程序启动时初始化中继:
SteamNetworkingUtils.InitRelayNetworkAccess();
- 点击按钮创建监听套接字:
listenSocket = SteamNetworkingSockets.CreateListenSocketP2P(0, 0, null);
- 点击按钮发起跨设备连接:
SteamNetworkingIdentity identityRemote = new SteamNetworkingIdentity(); if (SteamUser.GetSteamID() == new CSteamID("mySteamID")) identityRemote.SetSteamID64("anotherSteamID"); else identityRemote.SetSteamID64("mySteamID"); connectionSocket = SteamNetworkingSockets.ConnectP2P(ref identityRemote, 0, 0, null);
- 连接处理逻辑:检测到连接状态为
k_ESteamNetworkingConnectionState_Connecting时重复调用接受连接:
if (connectionState == ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_Connecting) { SteamNetworkingSockets.AcceptConnection(connectionSocket); }
问题现象
双方始终无法建立连接,一段时间后连接状态变为k_ESteamNetworkingConnectionState_ProblemDetectedLocally(超时)。已连续3天排查,查阅Steamworks文档、参考示例项目、尝试Facepunch.Steamworks(因习惯问题未适应),仍未解决。
排查与修复建议
1. 修正连接接受逻辑的触发时机
AcceptConnection不能在Connecting状态重复调用,正确的做法是仅在收到SteamNetConnectionStatusChangedCallback_t回调且状态为k_ESteamNetworkingConnectionState_RequestingConnection时调用一次,重复调用会干扰连接流程:
private void OnConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t callback) { var state = callback.m_info.m_eState; var connection = callback.m_hConn; switch (state) { case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_RequestingConnection: SteamNetworkingSockets.AcceptConnection(connection); break; case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_Connected: // 连接成功后的业务逻辑 break; case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_ProblemDetectedLocally: // 打印错误详情用于排查 Debug.WriteLine($"连接错误原因: {callback.m_info.m_szDebug}"); break; } }
2. 修复SteamID的使用方式
当前代码中用字符串包裹SteamID的写法会导致解析错误,必须传入纯数字的64位SteamID:
// 错误写法 new CSteamID("mySteamID"); // 正确写法(示例ID为12345678901234567) new CSteamID(12345678901234567); // SetSteamID64同理,直接传数字 identityRemote.SetSteamID64(12345678901234567);
同时要确保两台设备登录的Steam账号与目标SteamID完全匹配。
3. 验证中继网络与初始化顺序
- 确保
SteamNetworkingUtils.InitRelayNetworkAccess()在SteamAPI.Init()成功返回true之后调用 - 调用
SteamNetworkingUtils.GetRelayNetworkStatus()获取中继状态,打印返回值确认是否正常连接到Steam中继服务器 - 检查Steam后台游戏设置:确保启用P2P功能,测试账号已添加为Steam开发者测试用户
4. 绑定监听套接字的回调
创建监听套接字后,必须绑定连接状态变化的回调,否则无法收到对方的连接请求:
listenSocket = SteamNetworkingSockets.CreateListenSocketP2P(0, 0, null); // 绑定回调以接收连接状态变更通知 Callback<SteamNetConnectionStatusChangedCallback_t>.Create(OnConnectionStatusChanged);
5. 避免双向主动连接冲突
不要在检测到连接请求后发起反向连接,这会导致双方同时发起连接造成冲突。正确流程是:
- 单一方作为监听端创建套接字等待请求
- 另一方作为客户端主动调用
ConnectP2P发起连接 - 监听端收到
RequestingConnection状态时调用AcceptConnection
6. 打印详细错误日志
当连接状态变为ProblemDetectedLocally时,打印callback.m_info.m_szDebug和callback.m_info.m_eEndReason,这些信息会直接给出超时的具体原因(如中继不可达、防火墙拦截、SteamID错误等)。
内容的提问来源于stack exchange,提问作者Ailtairon

