HttpURLConnection

OpenJDK 1.7.0_75 で調べた。

http のとき URL.openConnection() で返って来るのは sun.net.www.protocol.http.HttpURLConnection。

HttpURLConnection.connect() で、sun.net.www.http.HttpClient を生成、保持する。Socket の管理は HttpClient の仕事。connect()時点では OutputStream を作るが InputStream はまだ。例えば HttpURLConnection.getResponseCode() のとき、内部で HttpURLConnection.getInputStream() が呼ばれる。

Socket の生成

HttpURLConnection.connect() -> HttpClient.openServer() -> NetworkClient.doConnect() -> new java.net.Socket() : impl = java.net.SocksSocketImpl (extends PlainSocketImpl)

Socket のクローズ

HttpURLConnection を disconnect() し忘れた場合、AbstractPlainSocketImpl で、finalize 時に Socket をクローズしている。よってGC時にクローズされる。(disconnect() 時の keepalive キャッシュの条件がイマイチ分からない。。。)

InputStream を最後まで読まず、disconnect() すると サーバ側で ClientAbortException が起こる。disconnect() せずに connection を放棄すると、GC時に突然 ClientAbortException が起こる(かもしれない)。

    protected void finalize() throws IOException {
        close();
    }
    protected void close() throws IOException {
        synchronized(fdLock) {
            if (fd != null) {
                if (!stream) {
                    ResourceManager.afterUdpClose();
                }
                if (fdUseCount == 0) {
                    if (closePending) {
                        return;
                    }
                    closePending = true;
                    /*
                     * We close the FileDescriptor in two-steps - first the
                     * "pre-close" which closes the socket but doesn't
                     * release the underlying file descriptor. This operation
                     * may be lengthy due to untransmitted data and a long
                     * linger interval. Once the pre-close is done we do the
                     * actual socket to release the fd.
                     */
                    try {
                        socketPreClose();
                    } finally {
                        socketClose();
                    }
                    fd = null;
                    return;
                } else {
                    /*
                     * If a thread has acquired the fd and a close
                     * isn't pending then use a deferred close.
                     * Also decrement fdUseCount to signal the last
                     * thread that releases the fd to close it.
                     */
                    if (!closePending) {
                        closePending = true;
                        fdUseCount--;
                        socketPreClose();
                    }
                }
            }
        }
    }