记录一次Minecraft联机异常解决过程

本文首发于:https://blog.heixb.top

Minecraft无法发现局域网游戏

环境说明

Minecraft : 1.12.2
网络环境 : 手机热点
服务端 : 客户端开放的局域网多人游戏

起因

和同学局域网联机Minecraft,但是部分人出现了几次无法正常搜索到局域网游戏的情况

故障排查

首先尝试简单的排查修复

网络连接问题

首先WiFi连接正常 然后互相能ping通 初步排除简单网络故障

防火墙

下一步我怀疑是防火墙问题 不过Windows10的防火墙实际上不大容易出问题,因为按照设计机制,当应用尝试联网的时候,会弹出请求提示框,申请连接网络 这时候点击同意后通常就没什么问题了 不过也可能存在误点拒绝或其他未知的情况

直接关闭各主机防火墙 然而即使关闭防火墙后,依然没有解决

网络适配器

这时候很容易怀疑到是网络适配器问题 之所以会想到这里是因为我们的电脑上均有虚拟机软件创建的虚拟网卡 猜测可能Minecraft客户端仅在单一的网络接口上搜索局域网游戏 在禁用掉多余的网络适配器之后,重新扫描游戏,成功搜索到服务端

问题初步解决

本来问题就应该就这样解决了的 但是因为我们在不同的网络环境(有线、无线)切换而进行联机 当出现问题的时候就需要再次禁用启用网络适配器 而我因为虚拟机使用得比较频繁,需要一直开启虚拟网卡 每次都来回禁用启用也比较烦 然后就冒出了想摸索一下造成这个问题是原因是什么

深入探究

这篇文章是在我解决之后才开始写的,我尽量还原当时的解决思路和过程,但也会有所修改 然后因为我对相关技术的了解度不够,可能会存在一些描述失误,还请谅解

Minecraft服务端机制

按照Minecraft Wiki – Setting up a LAN world中所述

On the technical side, a Minecraft client with an opened LAN game sends a UDP multicast to the local address 224.0.2.60:4445 every 1.5 seconds. Other clients then listen for this multicast to show your game in their multiplayer menu.

在技术层面,向局域网开放游戏的Minecraft客户端每1.5秒会向本地地址224.0.2.60:4445发送一个UDP多播。其他客户端会侦听此多播以把你的游戏显示在他们的多人游戏菜单中

看起来似乎没什么问题 服务端发送信息 -> 客户端监听到 -> 加入服务器

不过我对多播了解得并不深,仅限于与单播、广播区分

开始尝试排查

使用Wireshark监听我的WLAN(我们使用无线网络进行联机)

从图中看来,是能正常接受到来自服务端(192.168.43.70)的多播信息的 但是为什么这样都还是没法正常搜索到游戏呢

尝试查找解决方式

接着我搜索到了这篇文章Minecraft Local Server Discovery – Can’t find LAN games?

文中提到作者因为网络接口优先级的问题,导致Minecraft绑定了错误的端口

使用命令netsh interface ip show joins查看各个网络适配器加入的多播组 正常的输出类似于:

接口 16: WLAN
​
作用域       参照       上一次 地址
----------  ----------  ----   ---------------------------------
0                    0  是     224.0.0.1
0                    2  是     224.0.0.251
0                    1  是     224.0.0.252
0                    3  是     239.255.255.250
​
接口 23: 以太网
​
作用域       参照       上一次 地址
----------  ----------  ----   ---------------------------------
0                    0  否     224.0.0.1
0                    2  否     224.0.0.251
0                    1  否     224.0.0.252
0                    0  是     224.0.2.60
0                    3  是     239.255.255.250

从上面的输出可以看到,以太网接口加入了多播组224.0.2.60,但是我们进行联机的网络(WLAN)上并没有加入

这里我搜索了一些资料稍微了解了一下多播的机制

多播 – 百度百科

多播 – 维基百科

接下来按照作者提供的方式,使用以下命令调整网络接口优先级,将异常加入多播组的接口优先级调低,继而使Minecraft去选择正常(使用)的网络接口

get-netipinterface | where-object { $_.InterfaceAlias -like "网络接口名" } | set-netipinterface -interfacemetric 80

上面这条命令的作用是调整指定Windows设置中网络接口的跃点数(越小越优先,默认自动) 虽然我认为这样把希望连接的接口的跃点数调低似乎是更好的选择(网络适配器存在多个) 但是事实上这个机制我了解得不多

不过我发现调整了这个选项对我没有作用,并且调整这个项会影响其他网络连接(如上网)的优先级,未免就有些得不偿失了

但是这时候发现了一个问题,既然我的WLAN口没有加入多播组224.0.2.60,那么我最开始为什么能在WLAN接口监听到多播信息呢?

经朋友提醒,因为无线网络的工作方式是类似于Hub的 将信息发送给所有连接终端,然后由终端查看是否发送给自己的,从而决定是否丢弃 所以我能从WLAN接口上监听到多播包,但是事实上并没有接收处理

现在的思路是尝试手动使网络接口加入多播组,使Minecraft能监听到多播信息

然后我开始在搜索关于Windows使指定网络接口加入多播组的方式,但是废了一番功夫,并没有找到能简单实现的方式(命令)

解决

在一个帖子中发现有人提到Windows不提供直接加入的多播组的方式,需要实现的话可以通过socket实现

不过由于我对于socket并不太熟悉,这里直接参考别人的代码python实现多播数据的发送和接收

import socket 
​
ANY = str(input("输入IP:"))   # 输入希望加入多播组的网络适配器的IP
MCAST_ADDR = '224.0.2.60'   # 224.0.2.60是Minecraft服务端向局域网发送主机信息的多播地址
MCAST_PORT = 4445
​
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) #创建UDP socket
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #允许端口复用
sock.bind((ANY,MCAST_PORT))
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
status = sock.setsockopt(socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(MCAST_ADDR) + socket.inet_aton(ANY));
​
sock.setblocking(0)
​
while 1:
    try:
        data, addr = sock.recvfrom(1024)
    except BaseException:
        pass
    else:
        print("FROM: ", addr)
        print("DATA: ", data.decode('utf-8'))

保存为文件并执行后 从输出信息可以看到服务端的IP与端口,以及服务端的信息

再次执行netsh interface ip show joins可以看到,WLAN接口以及加入多播组

不过这种方式不太清楚是否能让Minecraft客户端正确搜索到服务端 因为实际上建立连接并监听的是Python,而不是Minecraft

查看Minecraft客户端 成功搜索到服务端信息

然而,整套流程下来,成功解决问题,但还是不清楚是怎么解决的 因为对于网络系统实现机制,以及Minecraft的网络发现机制不太清楚╮(╯▽╰)╭

不过相信总有一天回头再看看,会理解这一切