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

With the following snippet I bind to a specific interface

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 }

and then use this to as the local address for Listen. Does anybody have any idea what happens if the IP address of the interface changes?

This is a question that I believe will be best answered in terms of linux networking, not so much go language, since a go server will have to do the following to listen on the socket:

I describe the case for TCP server, but UDP server will be analogous (to a certain degree!). You can investigate it yourself by setting up a simple server and running it with strace, for example:

strace -e trace=network nc -l -s 192.168.0.1 7777 (strace part will display system calls and nc -l part will listen on the given address)

Output (I encourage you to try similar thing with a simple go server!):

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, 

We can see that the server blocks on accept call and waits for incoming connections. What happens here is specified more precisely in Linux man pages:

If no pending connections are present on the queue, and the socket is not marked as nonblocking, accept() blocks the caller until a connection is present. If the socket is marked nonblocking and no pending connections are present on the queue, accept() fails with the error EAGAIN or EWOULDBLOCK.

Now the question is how a packet that is received by an interface on the host gets to that socket. It needs to travel through the TCP/IP stack and finally arrive in our application. It is not a trivial process and you can find details on it in many linux networking guides). In essence, what happens is (this is VERY HIGH level description/generalization):

  1. Packet arrives at the Network Interface Card, gets classified and arrives at correct upper layer (e.g. IP in case of IP packets)
  2. Packet arrives at the IP layer, where IP header is checked among other things, and then IP header is stripped and packet being carried by this IP packet is passed to the upper layer (e.g. in case of TCP - to TCP layer)
  3. tcp_v4_rcv function is called from IP layer (in case of TCPv4), and the packet arrives at TCP layer. Here, header is checked and then an open socket for this incoming packet is being looked for (call to __tcp_v4_lookup).

At this stage, if the TCP socket for this packet is not found, the packet is discarded. Otherwise, the packed it passed to the process.

To directly answer your question: if IP address changes, and old TCP socket was bound to old IP address, the packet that is received for this socket (which will be still open is the server is running and is not refreshed) will be discarded somewhere along the journey through networking parts of linux kernel.

Here's a If you really want to go in-depth, a good description of what happens can be found in a great article Inside the Linux Packet Filter (and part 2 about what happens above IP layer)