Binding multiple times to the same port?

2019-04-12 17:22发布

问题:

Why doesn't the following code throw a "java.net.BindException: Address already in use: JVM_Bind" exception?

import java.net.InetSocketAddress;
import java.net.ServerSocket;

public class Test
{
    public static void main(String[] args) throws Exception
    {
        try (ServerSocket socket1 = new ServerSocket();
             ServerSocket socket2 = new ServerSocket();
             ServerSocket socket3 = new ServerSocket())
        {
            int port = 10000;

            socket1.setReuseAddress(false);
            socket1.bind(new InetSocketAddress("0.0.0.0", port));

            socket2.setReuseAddress(false);
            socket2.bind(new InetSocketAddress("127.0.0.1", port));

            socket3.setReuseAddress(false);
            socket3.bind(new InetSocketAddress("127.0.0.2", port));

            Thread.sleep(Long.MAX_VALUE);
        }
    }
}

Running 'netstat' afterwards displays:

C:\Users\Administrator>netstat -a -n | findstr 10000
  TCP    0.0.0.0:10000          0.0.0.0:0              LISTENING
  TCP    127.0.0.1:10000        0.0.0.0:0              LISTENING
  TCP    127.0.0.2:10000        0.0.0.0:0              LISTENING
  TCP    [::]:10000             [::]:0                 LISTENING

I am running this on Windows Server 2008 R2 (64-bit), and 'ipconfig /all' displays only one network adapter/interface (other network adapters are disabled). But, on some other machines, this program actually does throw the expected "java.net.BindException: Address already in use: JVM_Bind"!

What could be going on?

回答1:

You can bind on the same port number on different IP addresses. The operating system can distinguish the incoming packets by their target IP address as well as their TCP port number.

The operating system has no problem keeping a separate serverSocket for 127.0.0.1:1000 and 127.0.0.2:1000. It knows where each packet belongs - even if it opens a new connection.

Note that the IP address 0.0.0.0 is just that - an IP address (it is not a valid IP address in the sense IP packets could be sent there, but I can't any support for 0.0.0.0 == any either). If you want to listen on all addresses, supply null to the InetSocketAddress instead. At this point, you have a greater chance of getting the desired exception (unless the OS decides that wildcard listens have lower priority and don't really overlap specific listens, so they can bind both).

Also note that setting setReuseAddress will not affect the binding. It only affects some specifics of what connections get refused or accepted.

As a side note - what's the point of waiting three hundred million years?