给 socket 分配随机端口

客户端的 socket 不需要手动执行 bind 绑定地址,但这不意味着客户端 socket 真的不需要绑定端口,实际上是内核它帮我们做了这个操作,在执行 connect 时,内核发现没有绑定端口,就会自动选择一个合适的端口绑定到 socket 。

当然这不说明我们不能对客户端 socket 执行 bind 操作,对于客户端 socket,依旧可以执行 bind 操作把 socket 绑定到一个地址。

为什么客户端的 socket 会自动分配端口呢?

  1. 客户端的 socket 很多,每产生一个连接,就会创建一个 socket,我们无法准确得知有哪些端口没有被使用。
  2. 客户端的 socket 并不关心自己端口是多少,更多的关注是服务端的端口号,因此客户端 socket 可以任意指定,只要能够通信即可。

自动分配端口这一操作在内核中的体现在 net/inet_connection_sock.c:inet_csk_get_port()

就像上面所描述的,大多数场景,我们无法确切知道当前环境还有哪些端口可用,因此也无需绑定地址到 socket 。但是对于特定场景,还是需要给 socket 手动绑定地址。如代理程序对 UDP 代理时,要先在本地创建一个 socket 作为客户端发送数据的隧道,这个时候就要先指定好端口,然后再返回给客户端。

那么现在问题就来了,我怎么知道需要绑定哪个端口呢?上面也说了,我不知道有哪些可用的端口。同时,因为也没有执行 connect,此时也没有得到一个随机的端口,这种场景应该怎么处理?可以采取的做法是:给 socket 绑定一个 0 端口,让系统随机分配一个。

代码中赋值 add.sin_port = 0,就是告诉内核,我需要一个可用的随机的端口,请给我分配一个。然后内核就会分配了。

执行完后,再通过 getsockname 函数就可以得到系统分配的端口号了。示例代码:

发表评论