如果绑定到特定接口,然后 IP 发生更改,会发生什么情况?



使用以下代码片段,我绑定到特定接口

iface, err := net.InterfaceByName(ifaceName)
if err != nil {
return nil, fmt.Errorf("ERR: Error using interface %q: %q", ifaceName, err.Error())
}
addrs, err := iface.Addrs()
if err != nil {
return nil, fmt.Errorf("ERR: Error using interface %q: %q", ifaceName, err.Error())
}
if len(addrs) < 1 {
return nil, fmt.Errorf("ERR: Interface %q has no addresses?", ifaceName)
}
ipAddr := addrs[0].(*net.IPNet).IP
udpAddr := &net.UDPAddr { IP: ipAddr }

然后使用此地址作为侦听的本地地址。有没有人知道如果接口的IP地址发生变化会发生什么?

我认为这个问题最好用 linux 网络来回答,而不是 go 语言,因为 go 服务器必须执行以下操作才能侦听套接字:

  • 绑定到套接字
  • 接受

我描述了TCP服务器的情况,但UDP服务器将是类似的(在一定程度上!您可以通过设置一个简单的服务器并使用 strace 运行它来自己调查它,例如:

strace -e trace=network nc -l -s 192.168.0.1 7777(strace部分将显示系统调用,nc -l部分将侦听给定地址(

输出(我鼓励你用一个简单的go服务器尝试类似的事情!

bind(3, {sa_family=AF_INET, sin_port=htons(7777), sin_addr=inet_addr("192.168.0.1")}, 16) = 0
listen(3, 1)                            = 0
accept4(3, 

我们可以看到服务器在接受呼叫时阻止并等待传入连接。这里发生的情况在 Linux 手册页中更精确地指定:

如果队列中不存在挂起的连接,并且套接字 未标记为非阻塞,accept(( 阻止调用方,直到 存在连接。 如果套接字标记为非阻塞且否 队列中存在挂起的连接,accept(( 失败,并显示 错误 EAGAIN 或 EWILL 阻止。

现在的问题是主机上的接口接收的数据包如何到达该套接字。它需要通过TCP/IP堆栈,最终到达我们的应用程序。这不是一个微不足道的过程,您可以在许多 linux 网络指南中找到有关它的详细信息(。从本质上讲,发生的事情是(这是非常高级的描述/概括(:

  1. 数据包到达网络接口卡,进行分类并 到达正确的上层(例如,如果是 IP 数据包,则为 IP(
  2. 数据包到达 IP 层,其中 IP 标头在 其他事情,然后IP标头被剥离并且数据包被剥离 该 IP 数据包携带的数据包被传递到上层(例如,在 的 TCP - 到 TCP 层(
  3. tcp_v4_rcv函数是从 IP 层调用的(在 TCPv4 的情况下(, 数据包到达 TCP 层。在这里,检查标题并 然后正在查找此传入数据包的开放套接字 (致电__tcp_v4_lookup(。

在此阶段,如果未找到此数据包的 TCP 套接字,则会丢弃该数据包。否则,打包后它传递到进程。

直接回答您的问题:如果 IP 地址更改,并且旧的 TCP 套接字绑定到旧 IP 地址,则为此套接字接收的数据包(如果服务器正在运行且未刷新,该数据包仍将打开(将在通过 Linux 内核的网络部分的过程中丢弃在某个地方。

这是一个 如果你真的想深入了解,可以在一篇很棒的文章中找到对发生的事情的很好的描述 Linux 数据包过滤器内部(以及关于 IP 层上发生的事情的第 2 部分(

相关内容

最新更新