开发者

Socket creation with same host

开发者 https://www.devze.com 2023-03-07 20:07 出处:网络
In Java, when creating sockets with the same parameters (ignoring the fact that this code will throw a ConnectException):

In Java, when creating sockets with the same parameters (ignoring the fact that this code will throw a ConnectException):

Socket s1 = new Socket("127.0.0.1", 7575);
Socket开发者_开发百科 s2 = new Socket("127.0.0.1", 7575);

Is s1 equal to s2? I mean, will closing s1 have the same effect on s2?

If not, how can I close a socket I don't have a reference to (only having the ip and port it was created with).

Thanks.


s1 and s2 refer to two distinct Socket instances so closing one will have no direct effect on the other.

You would not get a ConnectException just because of two sockets connecting to the same address and port though. There is nothing stopping you connecting two sockets to the same target address and port as long as the target server is able to accept them. When you only specify the target address/port pair the operating system automatically assigns a local port for the socket from the ephemeral port range (numbering somewhere above 1024). What matters is that the (remote address, remote port, local address, local port) combination (known as a 4-tuple) is unique; this is how the socket is differentiated by the underlying TCP/IP stack when it needs to match incoming packets to their corresponding sockets and is how a server is able to accept multiple connections on the same port.

If you were to do:

    Socket s1 = new Socket();
    s1.bind(new InetSocketAddress("127.0.0.1", 7070));
    s1.connect(new InetSocketAddress("127.0.0.1", SERVER_PORT));

    Socket s2 = new Socket();
    s2.bind(new InetSocketAddress("127.0.0.1", 7070));
    s2.connect(new InetSocketAddress("127.0.0.1", SERVER_PORT));

then you would get a BindException on the second socket's bind attempt, since only server sockets are allowed to create sockets bound to the same source port. This is because during accept() the 4-tuple is fully known and its uniqueness can be determined. This SO question has more detail.

Here is a simple test class to demonstrate what happens when multiple sockets connect to the same target host and port:

public class ConnectTest {

static ServerSocket serverSock;
static List<Socket> acceptedSockets = Collections.synchronizedList(new ArrayList<Socket>());
static final int SERVER_PORT = 55555;

static class Server implements Runnable {
    @Override
    public void run() {
        try {
            serverSock = new ServerSocket();
            serverSock.bind(new  InetSocketAddress("127.0.0.1", 55555));
            while (true)
                { acceptedSockets.add(serverSock.accept()); }
        } catch (IOException e) { e.printStackTrace(); }
    }
}

public static void main(String[] args) throws Exception {
    new Thread(new Server()).start();

    List<Socket> clientSockets = new ArrayList<Socket>();
    // open 10 sockets to the same target address/port
    for (int i = 0; i < 10; i++) {
        Socket s = new Socket("127.0.0.1", 55555);
        System.out.println("Local address: " + s.getLocalSocketAddress() +
                "    Remote address: " + s.getRemoteSocketAddress());
        clientSockets.add(s);
    }

    // now close half
    for (Socket s : clientSockets.subList(0, 5))
            s.close();

    // now list them again
    System.out.println("\n\n Socket list after some closed:");
    for (Socket s : clientSockets) {
        if (s.isClosed()) {
            System.out.println("* Socket Closed *");
        } else {
            System.out.println("Local address: " + s.getLocalSocketAddress() +
                "    Remote address: " + s.getRemoteSocketAddress());
        }
    }
}

}

And the output will be something like:

Local address: /127.0.0.1:43088    Remote address: /127.0.0.1:55555
Local address: /127.0.0.1:43089    Remote address: /127.0.0.1:55555
Local address: /127.0.0.1:43090    Remote address: /127.0.0.1:55555
Local address: /127.0.0.1:43091    Remote address: /127.0.0.1:55555
Local address: /127.0.0.1:43092    Remote address: /127.0.0.1:55555
Local address: /127.0.0.1:43093    Remote address: /127.0.0.1:55555
Local address: /127.0.0.1:43094    Remote address: /127.0.0.1:55555
Local address: /127.0.0.1:43095    Remote address: /127.0.0.1:55555
Local address: /127.0.0.1:43096    Remote address: /127.0.0.1:55555
Local address: /127.0.0.1:43097    Remote address: /127.0.0.1:55555


 Socket list after some closed:
* Socket Closed *
* Socket Closed *
* Socket Closed *
* Socket Closed *
* Socket Closed *
Local address: /127.0.0.1:43093    Remote address: /127.0.0.1:55555
Local address: /127.0.0.1:43094    Remote address: /127.0.0.1:55555
Local address: /127.0.0.1:43095    Remote address: /127.0.0.1:55555
Local address: /127.0.0.1:43096    Remote address: /127.0.0.1:55555
Local address: /127.0.0.1:43097    Remote address: /127.0.0.1:55555

You can see firstly that all that is needed for the sockets to be unique is a single part of the 4-tuple to be different. Even though we are connecting from 127.0.0.1 to 127.0.0.1 port 55555, the fact that the source port is unique is enough.

The sockets are identified by their reference variables which correspond to socket descriptors when the JVM needs to ask the OS to perform operations, there is no way that they can be confused.

Forcing a socket to be closed when you don't own a reference to it is impossible I think. The only way to do it that I can think of would be to call out to the underlying operating system's native libraries (via JNI) or system utilities (using Runtime.getRuntime().exec(command) or similar). You would need to identify the connection by its 4-tuple and then request it be closed, but you would need to have elevated privileges to do so.


The answer is no. This won't behave like you are anticipating. Only one connection to a port can be established at any given time (excluding asynchronous calls which behave somewhat differently).

if you stepped through your code and checked, you should find that s1 is set to be connected while s2 is disconnected.

As for how to close a socket you don't have a reference to, it doesn't function that way. You must create the instance of the Socket and maintain it throughout the execution of your program. If the reference is lost or disposed of, I believe you must recreate the Socket object.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号