游戏有所更新
太吾9月28日更新了新的测试分支,“Frame - 框架调整测试”。此测试分支中使用命名管道与后端交互而非Socket,会解决因端口问题造成的本问题。需要注意的是此分支不知合适才会合并到主分支。
如果更新此分支或此分支合并后还遇到报本错误的,请根据上面的更新查找后台的日志。目前见到反馈有因为“Failed to initialize steam api”导致此报错。这个描述的意思是初始化Steam API失败,请通过Steam启动游戏,不要双击游戏本体启动。另有反馈通过管理员模式运行Steam可以解决此问题。
0x0 背景
心心念念等到太吾绘卷更新后,打开就见开门红报错 “由于目标计算机积极拒绝,无法连接”。 进度卡在40%进不去游戏。
去贴吧转了一圈看大家说关闭360可解,可我装的是火绒呀。按照经验此类问题应该是端口冲突导致游戏无法监听特定端口,排查到原因是由于开启Hyper-V后Windows预留了游戏监听的接口导致监听失败。下面给出解决方案,以及排查过程。
0x1 解决方案
管理员模式打开命令行或PowerShell,依次输入以下命令:
net stop winnat
netsh int ipv4 add excludedportrange protocol=tcp startport=51827 numberofports=1
net start winnat
命令来自https://github.com/docker/for-win/issues/3171#issuecomment-873970535
0x2 排查过程
首先查看游戏打印的日志,报错的调用链中有一行:GameData.GameDataBridge.GameDataBridge.CheckConnection()
,那么就反编译游戏看看这段代码的逻辑吧。
上DnSpy
定位到对应函数,代码如下:
// Token: 0x06001C33 RID: 7219 RVA: 0x00151408 File Offset: 0x0014F608
public static bool CheckConnection()
{
bool isCompleted = GameDataBridge._connectionTask.IsCompleted;
bool result;
if (isCompleted)
{
bool flag = !GameDataBridge._client.Connected;
if (flag)
{
TaskStatus status = GameDataBridge._connectionTask.Status;
StringBuilder stringBuilder = new StringBuilder(string.Format("CheckConnection: Connection task completed but connection not established: {0}.", status));
bool flag2 = status == TaskStatus.Faulted;
if (flag2)
{
stringBuilder.Append(string.Format(" Exception:\n{0}.", GameDataBridge._connectionTask.Exception));
}
throw new Exception(stringBuilder.ToString());
}
GameDataBridge._readingThread.Start();
GameDataBridge._writingThread.Start();
GameDataBridge._connectionTask = null;
GameDataBridge._connectionTimer = null;
result = true;
}
else
{
bool flag3 = GameDataBridge._connectionTask.Exception != null;
if (flag3)
{
throw new Exception(string.Format("CheckConnection: {0}", GameDataBridge._connectionTask.Exception));
}
bool flag4 = GameDataBridge._connectionTimer.ElapsedMilliseconds >= 3000L;
if (flag4)
{
throw new Exception("CheckConnection: Timeout when connecting to GameData module.");
}
result = false;
}
return result;
}
可以看到异常就是在这里抛出的,逻辑是GameDataBridge._connectionTask
检测失败后抛出异常,查看此Task
的初始化过程:
public static void Initialize()
{
GameDataBridge.ShouldDisconnect = false;
GameDataBridge._gameDataModuleInitializationState = 0;
GameDataBridge._client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
NoDelay = true,
SendBufferSize = 1048576,
ReceiveBufferSize = 1048576
};
GameDataBridge._connectionTask = GameDataBridge._client.ConnectAsync(new IPEndPoint(IPAddress.Loopback, 51827));
GameDataBridge._connectionTimer = Stopwatch.StartNew();
GameDataBridge._readingThread = new Thread(new ThreadStart(GameDataBridge.ReadInterProcessMessages))
{
IsBackground = false,
Name = "ReadInterProcessMessages"
};
GameDataBridge._writingThread = new Thread(new ThreadStart(GameDataBridge.WriteInterProcessMessages))
{
IsBackground = false,
Name = "WriteInterProcessMessages"
};
}
第11行可以看出游戏尝试连接了一个固定端口51827
,看到这个端口范围顿时想到可能是Hyper-V的问题,因为之前排查rclone
无法授权的问题有遇到过53682
端口无法监听。当时排查了很长时间直到谷歌到有老哥指向Windows 10
本身的问题。按印象中的关键词再次搜索最终定位到GitHub
问题:https://github.com/docker/for-win/issues/3171
根据回复的命令查看Windows
预留端口:
netsh int ipv4 show excludedportrange tcp
发现51827
确实在列表中:
那么再根据Issue
回复中老哥的解决方案排除此端口即可。排除后再次查看预留端口:
可以看到后面多了个*
号,此端口现在为用户自行预留而非被系统预留。应用就可以正常监听此端口了。具体监听逻辑在另一个进程./Backend/GameData.exe
的依赖库GameData.dll
里:
namespace GameData.GameDataBridge{
// Token: 0x06000C47 RID: 3143 RVA: 0x000850FC File Offset: 0x000832FC
public static void Initialize()
{
GameDataBridge._gameDataModuleInitializationState = 0;
GameDataBridge._listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
GameDataBridge._listener.Bind(new IPEndPoint(IPAddress.Loopback, 51827));
GameDataBridge._listener.Listen(1);
GameDataBridge._handler = GameDataBridge._listener.Accept();
GameDataBridge._handler.NoDelay = true;
GameDataBridge._handler.SendBufferSize = 1048576;
GameDataBridge._handler.ReceiveBufferSize = 1048576;
GameDataBridge._readingThread = new Thread(new ThreadStart(GameDataBridge.ReadInterProcessMessages))
{
IsBackground = false,
Name = "ReadInterProcessMessages"
};
GameDataBridge._readingThread.Start();
GameDataBridge._writingThread = new Thread(new ThreadStart(GameDataBridge.WriteInterProcessMessages))
{
IsBackground = false,
Name = "WriteInterProcessMessages"
};
GameDataBridge._writingThread.Start();
}
}
3 条评论
输入第二行命令出现另外一个程序正在进行,无法访问怎么办?
抱歉,我不太清楚各位的系统情况,哪个程序还有占用。看下文章更新的第一段内容,9月28日晚太吾有推新测试分支,应该能解决端口造成的问题。但不清楚这个分支的后续更新频率以及合适合并到主分支。
谢谢,总算能进游戏了