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.
精彩评论