HttpURLConnection 연결 프로세스를 설명 할 수 있습니까?


134

HTTPURLConnection웹 서비스에 연결하는 데 사용 하고 있습니다. 사용 방법을 알고 HTTPURLConnection있지만 작동 방식을 이해하고 싶습니다. 기본적으로 다음을 알고 싶습니다.

  • 어느 시점 HTTPURLConnection에서 주어진 URL에 연결을 시도합니까?
  • 어느 시점에서 연결을 성공적으로 설정할 수 있었는지 알 수 있습니까?
  • 한 단계 / 방법 호출로 연결을 설정하고 실제 요청을 전송합니까? 어떤 방법입니까?
  • 평신도의 기능 getOutputStream과 기능을 설명 할 수 있습니까 getInputStream? 연결하려는 서버가 다운되면 Exceptionat을 얻 습니다 getOutputStream. HTTPURLConnection내가 호출 할 때만 연결을 시작 한다는 의미 getOutputStream입니까? 어때요 getInputStream? 에서 응답 만받을 수 있기 때문에 아직 getInputStream요청을 보내지 getOutputStream않고 단순히 연결을 설정 한다는 의미 입니까? 수행 HttpURLConnection내가 호출 할 때 응답을 요청 서버로 돌아 가기 getInputStream?
  • openConnection단순히 새 연결 개체를 만들지 만 아직 연결을 설정하지 않았다고 말하는 것이 맞 습니까?
  • 읽기 오버 헤드 및 연결 오버 헤드를 어떻게 측정 할 수 있습니까?

답변:


184
String message = URLEncoder.encode("my message", "UTF-8");

try {
    // instantiate the URL object with the target URL of the resource to
    // request
    URL url = new URL("http://www.example.com/comment");

    // instantiate the HttpURLConnection with the URL object - A new
    // connection is opened every time by calling the openConnection
    // method of the protocol handler for this URL.
    // 1. This is the point where the connection is opened.
    HttpURLConnection connection = (HttpURLConnection) url
            .openConnection();
    // set connection output to true
    connection.setDoOutput(true);
    // instead of a GET, we're going to send using method="POST"
    connection.setRequestMethod("POST");

    // instantiate OutputStreamWriter using the output stream, returned
    // from getOutputStream, that writes to this connection.
    // 2. This is the point where you'll know if the connection was
    // successfully established. If an I/O error occurs while creating
    // the output stream, you'll see an IOException.
    OutputStreamWriter writer = new OutputStreamWriter(
            connection.getOutputStream());

    // write data to the connection. This is data that you are sending
    // to the server
    // 3. No. Sending the data is conducted here. We established the
    // connection with getOutputStream
    writer.write("message=" + message);

    // Closes this output stream and releases any system resources
    // associated with this stream. At this point, we've sent all the
    // data. Only the outputStream is closed at this point, not the
    // actual connection
    writer.close();
    // if there is a response code AND that response code is 200 OK, do
    // stuff in the first if block
    if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
        // OK

        // otherwise, if any other status code is returned, or no status
        // code is returned, do stuff in the else block
    } else {
        // Server returned HTTP error code.
    }
} catch (MalformedURLException e) {
    // ...
} catch (IOException e) {
    // ...
}

귀하의 질문에 대한 처음 3 답변은 위의 HTTP POST 예제에서 각 방법 옆에 인라인 주석으로 나열됩니다.

에서 로 getOutputStream :

이 연결에 쓰는 출력 스트림을 반환합니다.

기본적으로 나는 이것이 어떻게 작동하는지 잘 이해하고 있다고 생각하므로 평신도의 용어로 반복하겠습니다. getOutputStream기본적으로 서버에 데이터를 쓰려는 의도로 연결 스트림을 엽니 다 . 위의 코드 예에서 "메시지"는 게시물에 남겨진 주석을 나타내는 서버로 보내는 주석 일 수 있습니다. 이 표시되면 쓰기 위해 연결 스트림을 getOutputStream여는 중이지만을 호출 할 때까지 실제로 데이터를 쓰지 않습니다 .writer.write("message=" + message);

에서 ()는 getInputStream :

이 열린 연결에서 읽는 입력 스트림을 반환합니다. 데이터를 읽을 수있게되기 전에 읽기 시간 초과가 만료되면 반환 된 입력 스트림에서 읽을 때 SocketTimeoutException이 발생할 수 있습니다.

getInputStream반대입니다. 마찬가지로 연결 스트림 getOutputStream도 열리지 만 서버에서 데이터를 쓰지 않고 읽습니다. 연결 또는 스트림 열기에 실패하면가 표시 됩니다.SocketTimeoutException

getInputStream은 어떻습니까? getInputStream에서만 응답을 얻을 수 있기 때문에 getOutputStream에서 요청을 보내지 않고 단순히 연결을 설정한다는 의미입니까?

요청 전송과 데이터 전송은 서로 다른 두 가지 작업입니다. getOutputStream 또는 getInputStream 을 호출 url.openConnection()하면 서버에 연결 설정 요청을 보냅니다. 서버가 연결이 설정되었다는 승인을 다시 보내는 핸드 셰이크가 있습니다. 그런 다음 데이터를 보내거나받을 준비가 된 시점입니다. 따라서 요청을 작성하는 목적이 데이터를 전송하는 것이 아니라면 스트림을 열어 연결 을 설정하기 위해 getOutputStream을 호출 할 필요가 없습니다 .

평신도의 관점에서, getInputStream요청하는 것은 친구의 집에 전화를 걸어 "이봐, 내가 그 쌍의 바이스 그립을 빌려도 괜찮습니까?"라고 말하는 것과 같습니다. 친구가 "확실히 와라."라고 말함으로써 악수를 설정합니다. 그런 다음 연결이 이루어지고 친구 집으로 걸어 가서 문을 두드리고 바이스 ​​그립을 요청한 다음 집으로 돌아갑니다.

비슷한 예를 사용 getOutputStream하여 친구에게 전화를 걸어 "이봐, 내가 돈을 빚지고있다, 그것을 보낼 수 있니?" 돈이 필요하고 몸이 아파서 오랫동안 오래 간직한 친구는 "물론, 싸구려 놈 이여." 그래서 당신은 당신의 친구의 집으로 걸어 돈을 그에게 "POST". 그는 당신을 쫓아 내고 집으로 돌아갑니다.

이제 평신도의 모범으로 계속해서 몇 가지 예외를 살펴 보겠습니다. 친구에게 전화했는데 집에 없었다면 500 오류 일 수 있습니다. 친구가 항상 돈을 빌리는 데 지쳐서 전화를 걸고 연결이 끊긴 번호 메시지를 받았다면 404 페이지를 찾을 수 없습니다. 청구서를 지불하지 않아 휴대 전화가 죽은 경우 IOException이 될 수 있습니다. (참고 :이 섹션은 100 % 정확하지 않을 수 있습니다. 일반인의 관점에서 무슨 일이 일어나고 있는지에 대한 일반적인 아이디어를 제공하기위한 것입니다.)

질문 # 5 :

예, openConnection은 단순히 새 연결 객체를 생성하지만 설정하지는 않습니다. getInputStream 또는 getOutputStream을 호출하면 연결이 설정됩니다.

openConnection새로운 연결 객체를 만듭니다. 로부터 URL.openConnection의의 javadoc :

이 URL에 대한 프로토콜 핸들러의 openConnection 메소드를 호출하여 매번 새 연결이 열립니다.

openConnection을 호출하면 연결이 설정되고 인스턴스화 할 때 InputStream, OutputStream 또는 둘 다 호출됩니다.

질문 # 6 :

오버 헤드를 측정하기 위해 일반적으로 전체 연결 블록 주위에 매우 간단한 타이밍 코드를 다음과 같이 래핑합니다.

long start = System.currentTimeMillis();
log.info("Time so far = " + new Long(System.currentTimeMillis() - start) );

// run the above example code here
log.info("Total time to send/receive data = " + new Long(System.currentTimeMillis() - start) );

요청 시간과 오버 헤드를 측정하기위한 고급 방법이 있지만 이것이 일반적으로 내 요구에 충분합니다.

요청하지 않은 연결을 닫는 방법에 대한 자세한 내용은 언제 URL 연결이 닫히나요?를 참조하십시오 . .


안녕하세요. 감사!!! 그것은 실제로 자세한 설명이었고 귀하의 답변에 정말 감사드립니다. 대답을 올바르게 이해하면 아직 연결이 설정되지 않은 경우 getOutputStream과 getInputStream이 모두 연결을 설정합니다. getOutputStream을 호출하면 내부적으로 getInputStream을 호출하면 HTTPURLConnection은 getOutStream에서 이미 설정할 수 있으므로 더 이상 getInputStream에서 연결을 다시 설정하지 않습니다. HttpURLConnection은 getInputStream의 getOutputStream에서 설정할 수있는 모든 연결을 재사용합니다.
— Arci

계속 : 아니면 getOutputStream 및 getInputStream에 대해 새롭고 별도의 연결을 설정합니까? 또한 연결 오버 헤드를 얻으려면 getOutputStream 전후에 타이머를 넣을 수있는 적절한 장소입니다. 읽기 오버 헤드를 얻으려면 getInputStream 전후에 타이머를 놓을 적절한 장소입니다.
— Arci

javadoc이 getInputStream 및 getOutputStream : Returns an output stream that writes to this connection.및 에 대해 말하는 것을 기억하십시오 Returns an input stream that reads from this open connection.. 출력 스트림과 입력 스트림은 연결과 별개입니다.
— jmort253

8
HttpURLConnection 객체는 대상 URL에 도달 해야하는 시점에만 도달하는 것으로 보입니다. 예를 들어, 입력 및 출력 스트림이 있으며 연결이 열릴 때까지 아무것도 할 수 없습니다. 훨씬 간단한 경우는 연결을 초기화 한 다음 응답 코드를 확인하는 것 외에는 아무것도하지 않는 GET 작업입니다. 이 경우 getResponseCode () 메소드가 호출 될 때까지 실제로 연결되지 않습니다. 그렇지 않으면 연결 수명주기에 대한 훌륭한 설명과 탐색입니다.
— Spanky Quigman

1
나는 'UrlConnection'인스턴스와 기본 Tcp / Ip / SSL 연결, 두 가지 개념으로 혼란 스러웠습니다. 전자는 기본적으로 단일 HTTP 페이지 요청과 동의어입니다. 후자는 동일한 서버에 여러 페이지 요청을 수행하는 경우에만 한 번만 작성되는 것입니다.
— Tim Cooper


1

HTTPURLConnection은 어느 시점에서 주어진 URL에 연결을 시도합니까?

URL에 이름이 지정된 포트 (있는 경우), 그렇지 않으면 HTTP의 경우 80, HTTPS의 경우 443 나는 이것이 문서화되었다고 믿는다.

어느 시점에서 연결을 성공적으로 설정할 수 있었는지 알 수 있습니까?

예외없이 getInputStream () 또는 getOutputStream () 또는 getResponseCode ()를 호출 할 때

한 단계 / 방법 호출로 연결을 설정하고 실제 요청을 전송합니까? 어떤 방법입니까?

아뇨.

일반인의 용어로 getOutputStream 및 getInputStream의 기능을 설명 할 수 있습니까?

필요한 경우 먼저 연결 한 다음 필요한 스트림을 반환합니다.

연결하려는 서버가 다운되면 getOutputStream에서 예외가 발생합니다. getOutputStream을 호출 할 때 HTTPURLConnection이 연결을 시작하기 시작한다는 것을 의미합니까? getInputStream은 어떻습니까? getInputStream에서만 응답을 얻을 수 있기 때문에 getOutputStream에서 요청을 보내지 않고 단순히 연결을 설정한다는 의미입니까? getInputStream을 호출 할 때 HttpURLConnection이 서버로 돌아가서 응답을 요청합니까?

위 참조.

openConnection이 단순히 새로운 연결 객체를 생성하지만 아직 연결을 설정하지 않았다고 말하는 것이 맞습니까?

예.

읽기 오버 헤드 및 연결 오버 헤드를 어떻게 측정 할 수 있습니까?

연결 : getInoutStream () 또는 getOutputStream ()이 리턴하는 데 걸리는 시간을 사용하십시오 (둘 중 먼저 호출). 읽기 : 첫 번째 읽기 시작부터 EOS 가져 오기까지의 시간입니다.


1
OP는 어떤 포인트 연결이 설정되었고 어떤 시점에서 연결 상태를 알 수 있다고 생각합니다. 포트 URL이 연결되지 않았습니다. 이것이 openConnection () 및 getInoutStream () / getOutputStream () / getResponseCode ()으로 향한 것으로 추측됩니다.
— Aniket Thakur

1

HTTPURLConnection은 어느 시점에서 주어진 URL에 연결을 시도합니까?

분명히 설명 할 가치가 있습니다 .'UrlConnection '인스턴스가 있고 기본 Tcp / Ip / SSL 소켓 연결이 있습니다. 'UrlConnection'또는 'HttpUrlConnection'인스턴스는 단일 HTTP 페이지 요청과 동의어이며 url.openConnection ()을 호출 할 때 작성됩니다. 그러나 하나의 'url'인스턴스에서 여러 개의 url.openConnection ()을 수행하면 운이 좋으면 동일한 Tcp / Ip 소켓과 SSL 핸드 쉐이킹을 재사용 할 것입니다 ... 소켓을 설정하는 오버 헤드가 매우 높은 SSL을 사용하는 경우 동일한 서버에 많은 페이지 요청을 수행하는 것이 좋습니다.

참조 : HttpURLConnection 구현


0

저수준 패킷 교환을 캡처하기 위해 연습을했으며 getInputStream, getOutputStream, getResponseCode, getResponseMessage 등과 같은 작업에 의해서만 네트워크 연결이 트리거되는 것을 발견했습니다.

Dropbox에 파일을 업로드하기 위해 작은 프로그램을 작성하려고 할 때 캡처 된 패킷 교환은 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

아래는 내 장난감 프로그램과 주석입니다

    /* Create a connection LOCAL object,
     * the openConnection() function DOES NOT initiate
     * any packet exchange with the remote server.
     * 
     * The configurations only setup the LOCAL
     * connection object properties.
     */
    HttpURLConnection connection = (HttpURLConnection) dst.openConnection();
    connection.setDoOutput(true);
    connection.setRequestMethod("POST");
    ...//headers setup
    byte[] testContent = {0x32, 0x32};

    /**
     * This triggers packet exchange with the remote
     * server to create a link. But writing/flushing
     * to a output stream does not send out any data.
     * 
     * Payload are buffered locally.
     */
    try (BufferedOutputStream outputStream = new BufferedOutputStream(connection.getOutputStream())) {
        outputStream.write(testContent);
        outputStream.flush();
    }

    /**
     * Trigger payload sending to the server.
     * Client get ALL responses (including response code,
     * message, and content payload) 
     */
    int responseCode = connection.getResponseCode();
    System.out.println(responseCode);

    /* Here no further exchange happens with remote server, since
     * the input stream content has already been buffered
     * in previous step
     */
    try (InputStream is = connection.getInputStream()) {
        Scanner scanner = new Scanner(is);
        StringBuilder stringBuilder = new StringBuilder();
        while (scanner.hasNextLine()) {
        stringBuilder.append(scanner.nextLine()).append(System.lineSeparator());
        }
    }

    /**
     * Trigger the disconnection from the server.
     */
    String responsemsg = connection.getResponseMessage();
    System.out.println(responsemsg);
    connection.disconnect();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.