TCP 패킷이 부분적으로 확인되면 재전송 메커니즘은 어떻게 반응합니까?


12

TCP 클라이언트가 시퀀스 번호가 10000-20000 인 패킷을 TCP 서버로 보내는 경우 tcp는 seq_ack 20001의 ACK로 응답합니다.

클라이언트에서 TCP 패킷을 가로 채서 패킷을 2 tcp 세그먼트로 분할하면 하나는 seq를 10000에서 15000으로, 다른 하나는 seq를 15001에서 20000으로 분리합니다. 그러면이 두 TCP 세그먼트가 TCP 서버로 전송됩니다. 경로에서 두 번째 세그먼트가 손실되었다고 가정하십시오. TCP 서버는 seq_ack 15001로 ACK를 응답합니다.

TCP 클라이언트는 seq 10000에서 20000으로 통합 패킷을 보내지 만 클라이언트의 관점에서 15001으로 ACK를 얻으므로 이상합니다. 어떻게 반응할까요? 이론적으로 클라이언트는 순서 15001에서 20000으로 바이트를 다시 전송해야합니다. 즉 클라이언트가 순서 15001에서 새 패킷을 전송할 것입니다. 그러나 TCP 스택 구현의 실제는 어떻습니까?

TCP 전송 버퍼에서 TCP 세그먼트가 전송되면 세그먼트는 여전히 ACK까지 유지됩니다. ACK가 오면 세그먼트에 대한이 바이트는 버퍼에서 지워집니다. 송신 버퍼에 포인터가 있으며 ACK가 올 때 포인터는 ack_seq가 해당하는 위치를 가리 킵니다. ack_seq 아래에있는 바이트가 지워집니다. 이런 식으로 전체 세그먼트를 재전송 할 필요가 없습니까?

답변:


8

이를 선택적 승인 이라고 하며 RFC 2018에 정의 된 TCP 사양에 이미 포함되어 있습니다. 이렇게하면 클라이언트가 실제로 15001에서 20000 바이트를 재전송 할 수 있지만 (당신이 말한대로 분할 한 경우 다른 패킷 / 세그먼트에 있기 때문에 ) 더 흥미롭게도 순서가 잘못된 승인을 허용합니다.

RFC 2018에서 :

SACK 옵션을 포함하는 ACK를 수신 할 때, 데이터 송신자는 향후 참조를 위해 선택 승인을 기록해야한다. 데이터 송신자에게는 전송되었지만 아직 승인되지 않은 세그먼트를 순서 번호 순서로 포함하는 재전송 큐가있는 것으로 가정합니다.

TCP 사양에서는 지원 SACK이 필요 하지 않습니다 . 클라이언트 서버가 선택적 승인을 지원하지 않으면 10000에서 20000까지의 모든 바이트를 다시 전송해야합니다.

TCP 스택 구현에서 이론과 동일합니까?

특히 인터넷과 같은 네트워크에서 성능, 효율성 및 대기 시간 증가가 중요하므로 일반적 SACK 으로 지원됩니다.

그러나 실제로 언급 한대로 수동으로 패킷을 조작하더라도 이러한 가정은 적용됩니다. RFC 793에 따라 최소한 전체 데이터 창을 다시 전송해야하지만 수신자 수신 된 데이터가 적어도 유효 하다는 것을 알고 있습니다. 구현 세부 사항은 섹션 3.3- RFC 793의 시퀀스 번호 입니다.

선택적 승인 지원 여부에 관계없이 전체 프로세스에 대한 개요는 이 기사 (매우 유용한 다이어그램 포함)를 참조하십시오 .


TCP는 스트림 기반의 바이트 지향 프로토콜이기 때문에 조금 이상합니다. 왜 전체 세그먼트를 재전송해야합니까? SAKC가없는 TCP는 세그먼트 지향 스트림 프로토콜이지만 Sack이있는 TCP는 실제 바이트 지향입니다. RFC는 이에 대해 구체적으로 설명하지 않습니다.
misteryes

TCP 스택이 전송 버퍼를 관리하는 방법은 업데이트 된 질문에 쓴 것과 동일합니다.
misteryes

@misteryes 이 기사 는 프로세스를 개략적으로 보여줍니다 (좋은 다이어그램도 있습니다).
획기적인

추천 한 링크에서, 저자는 여전히 실제 바이트 지향 방식이 아닌 세그먼트 지향 방식으로 문제를 논의하는 것 같습니다. 그렇지 않습니까?
misteryes

1
이 질문을 게시하기 전에 SACK을 알고있었습니다. 처음에는 SACK 이이 질문과 관련이 있다고 생각하지 않습니다. 내 생각에 TCP가 바이트 지향적이 아니라 세그먼트 지향이라면 SACK도 동일해야합니다. SACK 가능과 SACK 불가능의 차이점은 SACK의 경우 TCP가 ack_seq의 시퀀스 홀을 허용한다는 것입니다. 그러나 시퀀스 홀이 세그먼트에 해당한다고 생각했습니다. 당신의 말에 따르면, 구멍은 세그먼트의 절반 / 부분이 될 수 있습니다.
misteryes

3

세그먼트 크기는 연결 수명 동안 변경 될 수 있습니다. 다행히 TCP는 개별 패킷이 이전에 전송 된 세그먼트 크기를 기록 할 필요가 없습니다. 따라서 다음을 수행합니다.

  1. ACK가 도착할 때마다 포인터를 승인되지 않은 첫 번째 바이트로 이동시키고 필요없는 버퍼를 버립니다.
  2. 재전송이 필요한 경우 (빠른 재전송 또는 시간 초과, 첫 번째 ACK 수신 직후가 아님 ) 포인터에서 승인되지 않은 첫 번째 바이트까지 현재 유효한 세그먼트 크기로 다시 보냅니다.

두 작업 모두이 바이트가 원래 전송 된 세그먼트 크기와 독립적으로 수행되므로 이론은 대부분의 구현과 일치해야합니다.

설명 할 몇 가지 배경을 알려 드리겠습니다.

TCP는 바이트 또는 세그먼트를 사용합니까? 응용 프로그램에 TCP는 바이트 스트림 인터페이스를 제공합니다. 또한 모든 헤더 필드와 내부 변수는 바이트 단위입니다. 그러나 정보를 전송하기 위해 TCP는 바이트 단위로 바이트를 전송하는 것이 상당히 낭비 적이므로 세그먼트 단위로 정보를 청크합니다. 어디에서나 바이트 카운터를 사용하면 연결 수명 동안 세그먼트 크기를 일정하게 유지할 필요가 없다는 이점이 있습니다.

  • 재전송시 SACK 피기 백과 같은 옵션이 도입되고 있습니다 (실제 구현에서는 거의 발생하지 않습니다)
  • 경로 MTU가 변경됩니다. 예를 들어 경로를 따라 하나의 링크가 하위 MTU로 변경되거나 병목 현상 MTU 링크가 발생합니다. 터널이 설정되거나 (VPN, PPPoE) 라우팅 프로토콜이 다른 MTU 링크를 선택할 때 발생합니다. 이는 조각화 안 함이 설정된 IPv4에서 발생합니다 (대부분의 최신 TCP의 경우 true). 항상 TCPv6에서).

BTW : 수신기는 바이트 스트림홀을 인식하는 경우 (즉, 패킷이 손실되었지만 다음 패킷이 도착한 경우) SACK을 사용하기 때문에 SACK가 여기에 답이 아닙니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.