问题

在调试 Unity 中的 WebSocket 插件时,发现在不同的操作系统上开启的端口并不一致,虽然是随机的端口,但是随机的范围不同。

配置防火墙需要了解开启端口的范围,所以查看源代码后得知 WebSocket 在绑定端口时使用了 Socket.Bind(addr, 0) 这种形式,即本地端口为 0

Mono 都是直接使用对应平台的 Socket,所以在查找资料时直接找对应平台的资料就可以。

原因

为何要指定本地端口为 0 呢?因为使用本地端口 0 来指定当前任意可用的端口。

官方定义:2.2. Ephemeral Port Selection - RFC 6056 - Port Randomization

下面链接中的第一个答案简单介绍了一下可不可以直接使用本地端口 0,最后提到了 IANA 将此端口作为保留端口,所以以此作为动态/私有端口的惯例是可以的。

networking - Is it possible to connect to TCP port 0? - Unix & Linux Stack Exchange

方案

Windows

For TCP/IP, if the port is specified as zero, the service provider assigns a unique port to the application from the dynamic client port range. On Windows Vista and later, the dynamic client port range is a value between 49152 and 65535. This is a change from Windows Server 2003 and earlier where the dynamic client port range was a value between 1025 and 5000.

bind function (Windows) - MSDN

查看:

1
2
3
4
netsh int ipv4 show dynamicport tcp
netsh int ipv4 show dynamicport udp
netsh int ipv6 show dynamicport tcp
netsh int ipv6 show dynamicport udp

修改:

1
2
3
4
netsh int ipv4 set dynamicport tcp start=10000 num=1000
netsh int ipv4 set dynamicport udp start=10000 num=1000
netsh int ipv6 set dynamicport tcp start=10000 num=1000
netsh int ipv6 set dynamicport udp start=10000 num=1000

注意:Windows 不同的版本对应的端口范围也是不同的,建议使用前先查询确定。

参考文档:The default dynamic port range for TCP/IP has changed in Windows Vista and in Windows Server 2008

Linux

IP_BIND_ADDRESS_NO_PORT (since Linux 4.2) Inform the kernel to not reserve an ephemeral port when using bind(2) with a port number of 0. The port will later be automatically chosen at connect(2) time, in a way that allows sharing a source port as long as the 4-tuple is unique. When connect(2) is called on an unbound socket, the socket is automatically bound to a random free port or to a usable shared port with the local address set to INADDR_ANY.

ip(7) - Linux manual page

查看:

1
$ cat /proc/sys/net/ipv4/ip_local_port_range

修改:

1
# sudo echo "49152 65535" > /proc/sys/net/ipv4/ip_local_port_range

参考文档:The Ephemeral Port Range

参考文档中给出了很多其他系统的查看与修改方法,如 FreeBSD、Solaris 等等。