Java套接字:bind()和connect()方法问题

时间:2017-11-02 05:35:41

标签: java sockets

执行以下程序后,为什么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");
    }
}

1 个答案:

答案 0 :(得分:1)

如果绑定到127.0.0.1,则只能连接到同一主机中的本地地址,因此无法连接到1.1.1.1。如果你没有绑定,connect()将选择一个适当的本地地址绑定到可以路由到目标地址。

connect()不是一个瞬时操作:它需要一个三向数据包交换。在这种情况下,您也无法连接到1.1.1.1,因此您获得了指定的4000ms连接超时。