执行以下程序后,为什么bind()
和connect()
方法会立即抛出异常?
不使用bind()
方法,connect()
方法阻止执行4秒。可能是什么原因?
package test1;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
public class Test73 {
public static void main(String[] args) throws IOException {
long beginTime = 0;
try {
Socket socket = new Socket();
System.out.println(socket.getPort());
System.out.println(socket.getLocalPort());
// socket.bind(new InetSocketAddress("localhost", 7777));
System.out.println(socket.getPort());
System.out.println(socket.getLocalPort());
beginTime = System.currentTimeMillis();
socket.connect(new InetSocketAddress("1.1.1.1", 8888), 4000);
System.out.println(socket.getPort());
System.out.println(socket.getLocalPort());
socket.close();
System.out.println("client end!");
} catch (Exception e) {
long endTime = System.currentTimeMillis();
System.out.println(endTime - beginTime);
e.printStackTrace();
}
}
}
底部代码是原生源代码,它是openJDK源代码。这个问题我觉得有了底层的C ++实现,所以底层的源代码已经发布了!
JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForConnect
(JNIEnv *env, jclass clazz, jint fd, jint timeout) {
int rv, retry;
int optlen = sizeof(rv);
fd_set wr, ex;
struct timeval t;
FD_ZERO(&wr);
FD_ZERO(&ex);
FD_SET(fd, &wr);
FD_SET(fd, &ex);
t.tv_sec = timeout / 1000;
t.tv_usec = (timeout % 1000) * 1000;
/*
* Wait for timeout, connection established or
* connection failed.
*/
rv = select(fd+1, 0, &wr, &ex, &t);
/*
* Timeout before connection is established/failed so
* we throw exception and shutdown input/output to prevent
* socket from being used.
* The socket should be closed immediately by the caller.
*/
if (rv == 0) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
"connect timed out");
shutdown( fd, SD_BOTH );
return;
}
/*
* Socket is writable or error occurred. On some Windows editions
* the socket will appear writable when the connect fails so we
* check for error rather than writable.
*/
if (!FD_ISSET(fd, &ex)) {
return; /* connection established */
}
/*
* Connection failed. The logic here is designed to work around
* bug on Windows NT whereby using getsockopt to obtain the
* last error (SO_ERROR) indicates there is no error. The workaround
* on NT is to allow winsock to be scheduled and this is done by
* yielding and retrying. As yielding is problematic in heavy
* load conditions we attempt up to 3 times to get the error reason.
*/
for (retry=0; retry<3; retry++) {
NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
(char*)&rv, &optlen);
if (rv) {
break;
}
Sleep(0);
}
if (rv == 0) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
"Unable to establish connection");
} else {
NET_ThrowNew(env, rv, "connect");
}
}
答案 0 :(得分:1)
如果绑定到127.0.0.1,则只能连接到同一主机中的本地地址,因此无法连接到1.1.1.1。如果你没有绑定,connect()
将选择一个适当的本地地址绑定到可以路由到目标地址。
connect()
不是一个瞬时操作:它需要一个三向数据包交换。在这种情况下,您也无法连接到1.1.1.1,因此您获得了指定的4000ms连接超时。