使用以下代码片段,我将绑定到特定接口
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地址更改会发生什么情况?
答案 0 :(得分:5)
我认为这是一个关于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或EWOULDBLOCK。
现在的问题是主机上接口接收的数据包如何到达该套接字。它需要经过TCP/IP stack,最后到达我们的应用程序。这不是一个微不足道的过程,您可以在许多linux networking guides中找到有关它的详细信息。本质上,会发生什么(这是非常高级的描述/概括):
tcp_v4_rcv
函数(对于TCPv4),
数据包到达TCP层。在这里,检查标头,
然后寻找此传入数据包的开放套接字
(致电__tcp_v4_lookup
)。在此阶段,如果找不到此数据包的TCP套接字,则将丢弃该数据包。否则,将其打包传递给进程。
直接回答您的问题:如果IP地址更改,并且旧的TCP套接字已绑定到旧的IP地址,则此套接字收到的数据包(如果服务器正在运行且未刷新,它将仍然打开)在整个Linux内核的网络连接过程中被丢弃。
这是一个 如果您真的想更深入,可以在一篇很棒的文章Inside the Linux Packet Filter(以及part 2中有关IP层之上发生的事情)中找到关于发生的事情的很好的描述