[HTTP] HTTP 커넥션 관리

서정범·2023년 4월 18일
0

HTTP

목록 보기
6/13

HTTP는 클라이언트와 서버 사이에 프락시 서버, 캐시 서버 등과 같은 중개 서버가 놓이는 것을 허락합니다.

어떤 경우에는, 두 개의 인접한 HTTP 애플리케이션이 현재 맺고 있는 커넥션에만 적용될 옵션을 지정해야 할 때가 있습니다. 이 때 사용하는 것이 HTTP Connection 헤더 필드이고, 이 값들은 다른 커넥션에 전달 되지 않습니다.

HTTP는 클라이언트와 서버 사이의 커넥션을 제공하는 TCP를 전송프로토콜로 주로 이용합니다. 즉, 여기서 말하는 HTTP 커넥션은 TCP커넥션이라고 생각할 수 있는 것 같다.

HTTP 커넥션과 중개 서버

위에서 언급했던 것은 HTTP 커넥션을 맺기 위해서 HTTP Connection 헤더 필드를 이용하고, 그것이 다른 커넥션에 전달 되어서는 안되며, 서버와 클라이언트 사이에는 중개 서버가 있다라는 내용을 언급했다.

그렇다는건 서버와 클라이언트 사이의 모든 중개 서버와 HTTP 커넥션을 각각 맺고 있다고 생각하는 것이 맞는 것일까?

맞는 내용일 것이다. 일단 데이터를 전달하기 위해선 캐시 서버이든 프록시 서버이든 커넥션이 필요로 하고, 커넥션을 맺지 않고 무책임하게 데이터를 그냥 던져 버리는 것은 아닐 것이다. 즉, 종단 간의 데이터 교환을 위해선 중간에 있는 모든 중개 서버와의 커넥션이 요구 되기 때문에 TCP를 이용할 경우 시간 지연이 크게 발생하는 것이다.

Connection 헤더에는 다음 세 가지 종류의 토큰이 전달됩니다.

  1. HTTP 헤더 필드 명: 이 커넥션에만 해당되는 헤더들을 나열
  2. 임시적인 토큰 값: 커넥션에 대한 비표준 옵션
  3. close 값: 커넥션이 작업이 완료되면 종료되어야 함을 의미

위에서도 말했지만, 해당 필드들은 현재 커넥션만을 위한 정보이므로 수신자는 모든 옵션을 적용한 후, 전송할 때 다음 커넥션에 전달되지 않게 삭제해야만 합니다.

Connection 헤더에는 홉별(hop-by-hop) 헤더 명을 기술하는데, 이것을 '헤더 보호하기'라고 합니다.

HTTP가 만약 순차적으로 트랜잭션을 처리한다고 생각해 보았을 경우, 아래와 같은 형태로 이루어 질 것입니다.

예를 들어서, 한 웹페이지를 사용자가 서버로부터 요청을 했을 경우 이 방식은 크게 두 가지 정도의 문제점이 있습니다.

  1. 이미지와 같은 것들이 하나하나 로드 될 것입니다.
  2. Render Tree 작동 방식으로 인해 사용자는 흰 색의 텅빈 화면을 보게 될 것

따라서, HTTP 커넥션의 성능을 향상시켜주는 4가지 기술을 볼 것입니다.

  1. 병렬(parallel) 커넥션: 여러 개의 TCP 커넥션을 통한 동시 HTTP 요청
  2. 지속(persistent) 커넥션: 커넥션을 맺고 끊는 데서 발생하는 지연을 제거하기 위한 TCP 커넥션의 재활용
  3. 파이프라인(pipelined) 커넥션: 공유 TCP 커넥션을 통한 병렬 HTTP 요청
  4. 다중(multiplexed) 커넥션: 요청과 응답들에 대한 중재(실험적인 기술)

병렬 커넥션

이 방식은 단일 커넥션의 대역폭 제한과 커넥션이 동작하지 않고 있는 시간을 활용하는 방식으로, 객체가 여러 개 있는 웹페이지를 더 빠르게 내려받을 수 있습니다.

즉, 한 개의 커넥션당 한 개의 커넥션을 맺는 것이 아니라, 한 개의 커넥션을 맺고 그것을 이용해서 여러 개의 객채를 전송하기 때문에 커넥션의 지연 시간을 줄일 수 있습니다. => 잘못된 표현

즉, 한 개의 객체를 전송하기 위해서 매번 한 개의 커넥션을 맺는 것보단, 한번에 동시에 전부 커넥션을 맺고 나서 동시에 전송하는 것이 시간적 측면에서 효율적이고, 커넥션의 총 지연 시간을 줄여줍니다.

또한, 한 개씩 객체를 보내는 것보다 여러 개의 객체를 보내는 것이 사용자가 동시에 객체를 받기 때문에 더 빠른 느낌을 느낄 수 있습니다.

단, 단점이 존재합니다.

만약, 클라이언트의 네트워크 대역폭이 좁을 때, 애초부터 느리기 때문에 병렬로 전송하는 이점이 없습니다.

또한, 다수의 커넥션메모리를 많이 소모하고 자체적인 성능 문제를 발생시킵니다.

따라서, 브라우저는 실제로 병렬 커넥션을 사용하긴 하지만 적은 수(대부분 4개)의 병렬 커넥션만을 허용합니다. 서버는 특정 클라이언트로부터 과도한 수의 커넥션이 맺어졌을 경우, 그것을 임의로 끊어버릴 수 있습니다.

지속 커넥션

지속 커넥션은 처리가 완료된 후에도 계속 연결된 상태로 있는 TCP 커넥션을 의미합니다.

이것은 사이트 지역성(site locality) 특징을 이용한 방식입니다.

앞서 봤던, 병렬 커넥션의 단점과 대비되는 지속 커넥션의 장점은 다음과 같습니다.

  • 커넥션을 맺기 위한 사전 작업과 지연을 줄여준다.
  • 튜닝된 컬렉션을 유지함으로써, TCP 느린 시작으로 인한 지연을 피한다.
  • 커넥션의 수를 줄여준다.

하지만, 단점도 존재하는데 지속 커넥션을 잘못 관리할 경우 계속 연결된 상태로 있는 수많은 커넥션이 쌓이면서 불필요한 소모가 발생합니다.

보통 지속 커넥션병렬 커넥션과 함께 사용하는 것이 효율적입니다.

지속 커넥션에는 두 가지 지속 커넥션 타입이 있습니다.

  • HTTP/1.0+에는 'keep-alive' 커넥션이 있고,
  • HTTP/1.1에는 '지속' 커넥션이 있습니다.

'Keep-Alive' 커넥션

초기의 지속 커넥션은 상호 운용과 관련된 설계에 문제가 있었습니다.

하지만 아직 많은 클라이언트와 서버가 이 초기 keep alive 커넥션하고 있습니다. 이 설계상의 문제는 HTTP/1.1에서 수정되었는데, 해당 부분에선 keep alive 커넥션이 무엇인지, 무슨 문제를 안고 있었는지, 어떻게 바뀌면서 해결이 되었는지 알아 볼 것입니다.

일단, 지속 커넥션 'keep alive' 커넥션을 이용하면서 기존에 매 트랜잭션마다 커넥션의 지연이 발생하는 것은 사라졌습니다.

문제점을 살펴보기 위해서 동작 과정과 옵션, 규칙등을 살펴보겠습니다.

동작 과정

HTTP/1.0 keep-alive 커넥션을 구현한 클라이언트는 커넥션을 유지하기 위해서 요청에 Connection:Keep-Alive 헤더를 포함시켜 보냅니다.

서버는 그 다음 요청도 이 커넥션을 통해 받고자 한다면, 응답 메시지에 같은 헤더를 포함시켜 보내야 합니다.

만약, 포함시키지 않고 보냈을 경우 클라이언트는 서버가 keep-alive를 지원하지 않으며, 응답 메시지가 전송되고 나면 서버 커넥션을 끊을 것이라고 추정합니다.

옵션

keep-alive의 동작은 Keep-Alive 헤더의 쉼표로 구분된 옵션들로 제어할 수 있습니다.

  • timeout 파라미터: 커넥션이 얼마간 유지될 것인지를 의미
  • max 파라미터: 몇 개의 HTTP 트랜잭션을 처리할 때까지 유지될 것인지를 의미
  • Keep-alive 헤더는 진단이나 디버깅을 주목적으로 하는, 처리되지 않는 임의의 속성들을 지원하기도 합니다.

Keep-Alive 커넥션 제한과 규칙

이 부분을 잘 이해해야 한다.

  • 클라이언트는 keep-alive 커넥션을 사용하기 위해 Connection:Keep-Alive 요청 헤더를 보내야 한다.
  • 커넥션을 계속 유지하려면 모든 메시지에 Connection: Keep-Alive 헤더를 포함해 보내야 합니다.
  • 만약 없이 보낸다면, 클라이언트는 서버가 응답 후에 커넥션을 끊을 것임을 알 수 있다.
  • 커넥션이 끊어지기 전엔티티 본문의 길이를 알 수 있어야 커넥션을 유지할 수 있습니다.
    • 트랜잭션이 끝나는 시점에 기존 메시지의 끝과 새로운 메시지의 시작점을 정확히 알아야 하기 때문입니다.
  • 프락시게이트웨이Connection 헤더의 규칙을 철처히 지켜야 합니다. 프락시와 게이트웨이는 메시지를 전달하거나 캐시에 넣기 전에 Connection 헤더에 명시된 모든 헤더 필드와 Connection 헤더를 제거해야 합니다.
  • 뒤에서 멍청한(dump) 프록시 개념이 나오는데, 이 프록시로 인해 keep-alive 커넥션은 Connection 헤더를 인식하지 못하는 프록시 서버와는 맺어져서는 안됩니다.
  • HTTP/1.0을 따르는 기기로부터 받는 모든 Connection 헤더 필드(Connection: Keep-Alive를 포함)는 무시해야 합니다. 오래된 프록시 서버로부터 실수로 전달될 수 있기 때문입니다.
  • 클라이언트는, 응답 전체를 모두 받기 전에 커넥션이 끊어졌을 경우, 별다른 문제가 없으면 요청을 다시 보낼 수 있게 준비되어 있어야 합니다. 그렇지 않으면 요청이 반복될 경우 문제 발생

Keep-Alive와 멍청한(dump) 프록시

앞서 말했지만, Connection 헤더에 담긴 필드들은 현재 커넥션만을 위한 것이고, 이것을 다른 커넥션에 전달해서는 안됩니다. 하지만, 멍청한 프록시 서버는 Connection 헤더에 담긴 필드들을 이해하지 못해서 해당 헤더들을 삭제하지 않고 요청 그대로를 다음 서버에 전달합니다.

다음 과정을 통해서 이해해보자.

1.클라이언트는 프록시에 Connection: Keep-Alive 헤더와 함께 메시지를 보내고, 커넥션 유지하기를 요청
2. 멍청한 프록시는 이 헤더를 이해하지 못하여 다음 서버에 메시지를 그대로 전달합니다. (여기서 문제점은 Connection 헤더는 홉별(hop-by-hop)헤더라는 것 => 오직 한 개의 전송 링크에만 적용되며 다음 서버로 전달 X)
3. 전달된 HTTP 요청이 서버에 도착. 웹 서버는 이 헤더를 받으며 프록시가 커넥션을 유지하자고 잘못된 판단을 합니다. 따라서, 웹 서버는 프록시와 keep-alive 커넥션이 맺어져 있는 상태로 keep-alive 규칙에 맞게 통신을 하는 것으로 판단. 프록시는 이해하지 못함
4. 멍청한 프록시는 서버로부터 받은 Connection:Keep-Alive 헤더를 포함하고 있는 응답 메시지를 클라이언트에게 전달. 클라이언트는 이 헤더를 통해 프록시가 커넥션을 유지하는 것에 동의 했다고 판단. 3번과 같은 맥락으로 서로 잘못된 이해관계 발생
5. 프록시는 keep-alive를 이해하지 못해, 받았던 모든 데이터를 그대로 클라이언트에게 전달하고 나서 서버가 커넥션을 끊기를 기다린다. 하지만, 서버는 커넥션을 끊지 않고 프록시는 계속 기다린다.
6. 클라이언트가 요청 메시지를 받고, 다음 요청을 보내기 시작하는데 프록시는 같은 커넥션 상에서 다른 요청이 오는 경우를 예상하지 못하여 요청을 무시하고 브라우저는 아무런 응답 없이 로드 중이라는 표시만 나온다.
7. 이런 잘못된 통신 때문에, 브라우저는 자신이나 서버가 타임아웃이 나서 커넥션이 끊길 때까지 기다린다.

이러한 문제점을 해결하기 위해 Proxy-Connection이 나온다.

Proxy-Connection

넷스케이프는 멍청한 프록시 문제를 해결하기 위해 브라우저에서 일반적으로 전달하는 Connection 헤더 대신에 비표준인 Proxy-Connection 확장 헤더를 프록시에게 전달합니다.

프록시가 Proxy-Connection을 무조건 전달하더라도 웹 서버는 그것을 무시하기 때문에 별 문제가 발생하지 않는다.

하지만, 영리한 프록시(지속 커넥션 핸드셰이킹을 이해할 수 있는)라면, 의미 없는 Proxy-Connection 헤더를 Connection 헤더로 바꿈으로써 원하는 효과를 얻게 될 것이다.

본인은 여기서 굉장히 헷갈렸습니다. 일단 아래에 동작에 관해서 정리하고 사진까지 올리고나서 이야기를 이어나가겠습니다.

멍청한 프록시의 경우, Proxy-Connection 헤더가 웹 서버에 전달되더라도 클라이언트와 프록시 사이 혹은 프록시와 서버 사이에 keep-alive 커넥션이 맺어지지 않습니다.

영리한 프록시의 경우, Proxy-Connection 헤더가 keep-alive를 요청하는 것을 인식하여, keep-alive 커넥션을 맺기 위해 자체적으로 Connection: Keep-Alive 헤더를 웹 서버에 전송합니다.

여기서 본인이 헷갈렸던 부분에 대해서 정리를 하고 넘어가겠습니다.

먼저, Proxy-Connection 헤더를 사용함으로써 무엇을 해결한 것인가를 생각해 보았습니다.

Keep-Alive 헤더를 보내면 멍청한 프록시는 무조건 전달을 함으로써 서버에 전달하지만, 서버는 이것을 전달 받아도 비표준이기에 무시를 해버립니다. 즉, 응답조차 날리지 않기에 Keep-Alive 커넥션은 이루어지지 않습니다.

만약, 영리한 프록시라면 Keep-Alive 헤더를 인식하기 때문에 이것을 표준인 Connection 헤더의 형태로 바꿔서 서버에 전달하고 응답 또한 클라이언트에게 전달한다고 합니다.

여기서 먼저 든 생각은 "그러면 즉, 멍청한 프록시 혹은 영리한 프록시중에서 선택을 해서 Keep-Alive를 맺고 안맺고 하려는 것인가?" 이였습니다.

하지만, 여기서도 의문점이 생겼습니다. 앞에서는 분명 프록시를 통해서 Connection 응답 헤더 필드를 클라이언트에게 건네주면서 문제가 발생했는데, 왜 영리한 프록시는 전달하는 것은 괜찮다는 식으로 설명이 써있는 것인가였습니다.

결론영리한 프록시지속 커넥션 핸드셰이킹을 이해할 수 있기에 클라이언트 - 중개 서버 - 서버 사이에 지속 커넥션이 이루어져도 커넥션을 인지하고 있기에 문제가 생기지 않고, 멍청한 프록시는 Proxy-Connection을 그대로 넘겨주면서 발생하는 에러 사항을 해결해주는 용도로써 활용되는 것 같습니다.

하지만 이마저도 만약 멍청한 프록시와 영리한 프록시가 커넥션 상에 같이 있다면 문제가 발생하는 것을 쉽게 생각할 수 있습니다.

이 외에도 프록시들은 방화벽, 캐시 서버, 혹은 리버스 프록시 서버 가속기와 같이 네트워크 상에서 '보이지 않는'경우들이 존재하기 때문에 보이지 않는 웹 애플리케이션들이 지속 커넥션들을 명확히 구현하는 것이 중요합니다.

지속 커넥션

HTTP/1.0의 keep-alive 커넥션과는 달리 HTTP/1.1의 지속 커넥션은 기본으로 활성화되어 있습니다. HTTP/1.1에서는 별도 설정(Connection: close 헤더)을 하지 않는 한, 모든 커넥션지속 커넥션으로 취급합니다.

⚡️ "keep-alive"와 지속 커넥션의 차이 ⚡️

keep-alive가 가지고 있던 문제점들에 대해 정리를 해보고, 지속 커넥션은 이것을 개선하기 위해 어떤 기능들을 제공하는지 알아봅시다.

"keep-alive" 문제점

1. 명시적인 헤더 필요: HTTP/1.0에서 커넥션을 지속시키기 위해서는 클라이언트와 서버 모두가 'Connection: keep-alive' 헤더를 명시적으로 사용해야 했습니다. 이는 추가적인 구성을 필요로 했으며, 모든 클라이언트와 서버에서 이를 지원하지 않았습니다.
2. 비표준화된 구현: 'keep-alive'는 HTTP/1.0의 표준이 아닌 확장 기능이었으며, 다양한 웹 서버와 클라이언트에서 서로 다르게 구현되었습니다. 이로 인해 호환성 문제가 발생할 수 있었습니다.
3. 프록시 서버 문제: 일부 프록시 서버들이 'keep-alive' 연결을 제대로 처리하지 못하는 문제가 있었습니다. 이는 커넥션이 예기치 않게 종료되거나 지속되는 문제를 일으킬 수 있었습니다. -> "멍청한 프록시"

HTTP/1.1의 지속 커넥션 개선

  • 기본적인 지속 커넥션: HTTP/1.1에서는 커넥션은 기본적으로 지속적(persistent)입니다. 즉, 별도의 'Connection: keep-alive' 헤더 없이도 커넥션이 유지됩니다. 이는 네트워크 오버헤드를 줄이고 성능을 향상시킵니다.
  • 커넥션 종료 표시: 커넥션을 종료하려면 'Connection: close' 헤더를 사용합니다. 이는 서버나 클라이언트가 명시적으로 커넥션을 종료하고자 할 때 사용됩니다.
  • 표준화된 프로토콜: HTTP/1.1의 지속 커넥션은 표준의 일부로서, 이에 대한 구현이 보다 일관되고 예측 가능해졌습니다.

지속 커넥션의 제한과 규칙

  • 클라이언트가 요청에 Connection: close 헤더를 포함해 보냈으면, 클라이언트는 그 커넥션으로 추가적인 요청을 보낼 수 없습니다.
  • 커넥션에 있는 모든 메시지가 자신의 길이 정보를 정확히 가지고 있을 때만 커넥션을 지속시킬 수 있습니다.
  • HTTP/1.1 프록시는 클라이언트와 서버 각각에 대해 별도의 지속 커넥션을 맺고 관리해야 합니다.
  • HTTP/1.1 프록시 서버는 클라이언트가 커넥션 관련 기능에 대한 클라이언트의 지원 범위를 알고 있지 않는 한 지속 커넥션을 맺으면 안됩니다. (오래된 프록시)
  • 서버는 언제나 커넥션을 끊을 수 있고, HTTP/1.1 애플리케이션은 중간에 끊어지는 커넥션을 복구할 수 있어야 합니다.
  • 하나의 사용자 클라이언트는 서버의 과부화를 방지하기 위해, 넉넉잡아 두 개의 지속 커넥션만을 유지해야 합니다.

파이프라인 커넥션

HTTP/1.1은 지속 커넥션을 통해 요청을 파이프라이닝할 수 있습니다.

파이프라인에는 여러 가지 제약 사항이 존재합니다.

  • HTTP 클라이언트는 커넥션이 지속 커넥션인지 확인하기 전까지 파이프라인을 이어서는 안됩니다.
  • HTTP 응답은 요청 순서와 같게 와야 합니다. HTTP 메시지는 순번이 매겨저 있지 않아서 응답이 순서 없이 오면 순서에 맞게 정렬시킬 방법이 없습니다.
  • HTTP 클라이언트는 커넥션이 언제 끊어지더라도, 완료되지 않은 요청이 파이프라인에 있으면 언제든 다시 요청을 보낼 준비가 되어 있어야 합니다.
  • HTTP 클라이언트는 POST 요청(비멱등 요청)같이 반복해서 보낼 경우 문제가 생기는 요청은 파이프라인을 통해 보내면 안됩니다. 에러가 발생하면 파이프라인을 통한 요청 중에 어떤 것들이 서버에서 처리되었는지 클라이언트가 알 방법이 없기 때문입니다.

커넥션 끊기

커넥션 관리(특히 언제 어떻게 커넥션을 끊는가)에는 명확한 기준이 없습니다.

먼저 '마음대로' 커넥션 끊기를 보자면 다음과 같습니다.

어떠한 HTTP 클라이언트, 서버, 혹은 프락시든 언제든지 TCP 전송 커넥션을 끊을 수 있습니다.

예를 들어, 지속 커넥션이 일정 시간동안 요청을 전송하지 않고 유휴 상태에 있으면 서버는 그 커넥션을 끊을 수 있습니다.

하지만, 끊는 시점에 서버는 클라이언트가 데이터를 전송하지 않을 것이라고 확신을 할 수 없습니다. 만약 보내는 도중이였을 경우 문제가 발생합니다.

Content-Length와 Truncation

각 HTTP 응답은 본문의 정확한 크기 값을 가지는 Content-Length 헤더를 가지고 있어야 하는 것은 앞에서 계속해서 확인했습니다. 일부 오래된 HTTP 서버는 자신이 커넥션을 끊으면 데이터 전송이 끝났음을 의미하는 형태로 개발되어 잘못된 정보로 응답하는 경우가 있기 때문에 주의해야 합니다.

즉, 실제 전달된 엔터티의 길이와 Content-Length 값이 일치하지 않거나 Content-Length자체가 존재하지 않으면 수신자는 서버에게 물어봐야 합니다.

만약 수신자가 캐시 프락시일 경우 응답을 캐시하면 안되고, 프락시는 Content-Length를 정정하려하지 말고 메시지를 받은 그대로 전달해야 합니다.

커넥션을 끊을 때 주의할 점은 또 있습니다.

클라이언트가 트랜잭션을 수행 중에 전송 커넥션이 끊기게 되면, 클라이언트는 그 트랜잭션을 재시도 하더라도 문제가 없다면 다시 맺고 재전송을 시도해야 합니다.

이 부분에서 클라이언트는 여러 요청을 큐에 쌓아 놓을 수 있지만, 서버는 아직 처리되지 않고 스케줄이 조정되어야 하는 요청들을 남겨둔 채로 커넥션을 끊어버릴 수 있습니다.

이렇게 되면 클라이언트는 서버가 얼마만큼 요청을 처리했는지 알수가 없습니다.

그냥 단순히 GET 하는 부류의 요청들은 반복적으로 요청하더라도 문제가 없지만, 예를 들어 온라인 스토에서 '주문'과 같은 POST 하는 부류의 요청들은 반복될 경우 문제가 생깁니다.

한번 혹은 여러 번 실행됐는지에 상관없이 같은 결과를 반환한다면 그 트랜잭션은 멱등(idempotent)하다고 합니다.

따라서, 클라이언트는 비멱등 요청은 파이프라인을 통해 요청하면 안됩니다.

우아한 커넥션 끊기

TCP 커넥션의 양쪽에는 데이터를 읽거나 쓰기 위한 입력 큐와 출력 큐가 있습니다.

애플리케이션은 TCP 입력 채널과 출력 채널 중 한 개만 끊거나 둘 다 끊을 수 있습니다.

  • close()를 호출하면 둘 다 끊을 수 있고, 이것을 '전체 끊기'라고 합니다.
  • shutdown()를 호출하면 둘 중 하나를 개별적으로 끊을 수 있고, 이것을 '절반 끊기'라고 합니다.

애플리케이션은 예상치 못한 쓰기 에러를 발생하는 것을 예방하기 위해 '절반 끊기'를 사용해야 합니다.

보통 커넥션의 출력 채널을 끊는 것이 안전합니다. 모든 데이터를 버퍼로부터 읽고 나서 데이터 전송이 끝남과 동시에 커넥션을 끊었다는 것을 알게 됩니다.

만약 클라이언트에서 이미 끊긴 입력 채널에 데이터를 전송할 경우, 서버의 운영체제는 TCP 'Connection reset by peer'메시지를 클라이언트에게 보내게 됩니다. 대부분 운영체제에서 이것을 심각한 에러로 취급하여 버퍼에 저장된, 아직 읽히지 않은 데이터를 모두 삭제합니다.

우아하게 커넥션 끊기는 일반적으로 애플리케이션 자신의 출력 채널을 먼저 끊고 다른 쪽에 있는 기기의 출력 채널이 끊기는 것을 기다리는 것입니다.

이렇게 하더라도 상대방이 '전체 끊기'를 한건지, '절반 끊기'를 한건지 알 수 없기에 애플리케이션은 출력 채널에 절반 끊기를 하고 난 후에도 데이터나 스트림의 끝을 식별하기 위해 입력 채널에 대해 상태 검사를 주기적으로 해야 합니다.


Reference

profile
개발정리블로그

0개의 댓글