TCP 네이글 알고리즘( Nagle Algorithm )이란?


  • TCP의 네이글 알고리즘이 활성화 되어있는 상태에서 데이터를 송신할 때 바로 송신하지 않고 최대 MSS( TCP 세그먼트 페이로드의 최대 크기를 의미하며 보통 1460byte입니다. )크기 만큼 데이터를 버퍼링하여 송신합니다.




네이글 알고리즘을 사용하는 이유


  • 송신할 데이터를 버퍼링하지 않고 Send 버퍼에 데이터가 적재될 때마다 송신한다면 패킷 마다 TCP 헤더, IP 헤더, 이더넷 헤더가 붙기 때문에 네트워크 트래픽량이 증가됩니다. 그렇기 때문에 송신할 데이터는 최대한 버퍼링하여 한 번에 송신하는 것으로 네트워크 트래픽을 줄일 수 있습니다.




네이글 알고리즘이 활성화 되었을 때 데이터 전송 조건


  • 송신하려는 데이터가 MSS 크기만큼 버퍼링 되었을 때 송신합니다.

  • 버퍼링하는 도중에 일정 시간이 지났다면 MSS 크기만큼 버피링 되어 있지 않더라도 송신합니다.

  • 데이터를 버퍼링 하는 도중에 상대방으로부터 ACK가 왔다면 MSS 크기만큼 버퍼링 되어 있지 않더라도 데이터를 송신합니다.




네이글 알고리즘의 단점


  • 송신하려는 데이터를 MSS만큼 버퍼링하고 송신하기 때문에 매우 빠른 응답성을 요구하는 격투 게임같은 경우에서는 사용자가 딜레이를 느낄 수 있습니다.




네이글 알고리즘을 비활성화하는 방법


  • setsockopt 함수를 통해 TCP_NODELAY 옵션을 주면 네이글 알고리즘을 비활성화 할 수 있습니다.




TCP의 세 가지 제어 기능

 

  • TCP는 흐름 제어, 오류 제어, 혼잡 제어 이 세 가지 제어 기능으로 안정적인 1:1 송.수신을 구현합니다. 이러한 기능들 덕분에 TCP를 사용할 경우 상위 레이어에만 개발에 집중할 수 있습니다.




흐름 제어

 

  • 흐름 제어는 상대방의 window size를 고려하여 송신 데이터의 크기를 조절하고 응답에 상관없이 window size만큼 데이터를 연속적으로 송신하는 기능을 담당합니다.




Stop and wait

 

 

  • 데이터를 송신하면 상대방이 데이터를 잘 수신 받았는지 여부를 확인하기 위해 ACK 응답을 기다립니다. ACK 응답의 Acknowledge Number를 통해서 수신 여부 및 정말로 보낸 데이터 만큼 잘 수신 받았는지를 확인할 수 있습니다.




Sliding window

 

 

  • sliding window는 TCP가 3-way-hasdshake 과정에서 알아냈던 상대방의 window size만큼 수신 응답을 기다리지 않고 데이터를 연속적으로 보내며 수신자 측은 지금까지 수신받았던 데이터 크기와 Sequence Number를 기반으로 Acknowledge Number를 셋팅하여 한 번에 응답합니다. 이러한 기능 덕분에 TCP의 패킷 당 송.수신 확인 응답으로 인한 지연을 줄일 수 있습니다.




오류 제어

 

  • TCP는 일정시간 수신자에게 응답이 없거나 송신 데이터가 잘못되어 NACK(Negative Ack)로 응답이 올 경우 자동으로 재전송하는 ARQ(Automatic Repeat Request) 기법을 사용합니다. 그리고 TCP는 Checksum과 Sequence Number, Acknowledge Number를 이용해서 송.수신 데이터의 오류를 검출하며 Go Back N, Selective Repeat을 혼합한 형태로 오류 제어를 합니다.(Stop and Wait 전송 속도가 매우 느리고 효율이 낮아서 사용되지 않습니다.)




Stop and Wait

 

 

  • 데이터를 송신하고 수신자로부터 일정시간 동안 ACK 응답이 없어 timeout이 되거나 NACK가 올 경우 전송했던 데이터를 재전송합니다.




Go Back N ( GBN )

 

 

  • Go Back N 방식은 위와 같이 sliding window를 이용해 연속적으로 데이터를 보내다가 timeout으로 데이터가 유실되었음을 인지하거나 수신자로부터 NACK 응답이 왔을 경우 문제가 발생된 데이터부터 다시 재전송하는 방식을 말합니다. 구현은 간단하지만 잘못된 데이터부터 모두 다시 보내야 한다는 단점이 있습니다.




Selective Repeat( SR )

 

 

  • Selective Repeat은 모든 응답에 대해서 ACK를 보내고 누락되거나 잘못된 패킷에 대해서만 NACK를 통해 재전송 요청을 합니다. 중간에 잘못되거나 누락된 패킷이 재전송되어 수신할 경우 기존에 받았던 패킷들과 순서에 맞게 재조합을 해야하기 때문에 추가적인 작업과 버퍼가 필요합니다. 또한 모든 패킷에 대한 응답이 필요하기 때문에 네트워크 트래픽이 증가될 수 있습니다.

 

  • 데이터를 연속적으로 송신하다가 중간의 데이터가 유실되어 동일한 ACK가 지속적으로 올 경우 timeout을 기다리지 않고 데이터가 유실되었다고 판단하여 재전송합니다.




혼잡 제어

 

 

  • 통신하는 네트워크 내의 트래픽이 과도하게 증가하여 송.수신이 원활하게 이루어지지 않는 상태를 혼잡이라고 합니다. TCP가 패킷 유실률 그리고 응답 속도를 종합하여 혼잡도를 판단합니다. 그리고 혼잡 제어는 네트워크의 혼잡한 현상을 방지하고 제거하기 위해 사용되는 기능입니다.




Awnd( Advertised window )와 Cwnd( Congention window)

 

  • Awnd는 실제로 수신자가 한 번에 데이터를 수신받을 수 있는 최대 버퍼 크기를 의미합니다.

 

  • Cwnd는 TCP가 네트워크 혼잡도에 따라서 실제로 수신자에게 한 번에 송신할 수 있는 데이터 크기를 의미하며, 최대 크기는 Awnd입니다.




Slow Start

 

  • TCP는 처음 연결직후 Cwnd의 사이즈를 1로 하고 임계 지점을 Awnd의 1/2로 합니다. 수신자로부터 ACK 응답을 받을 때마다 Cwnd 사이즈를 2베씩 증가시켜가며 Cwnd가 임계 지점에 도달했다면 ACK 응답을 받을 때마다 1씩 증가시켜 Awnd 크기 만큼 증가시킵니다.

 

  • timeout이 발생되었다면 네트워크가 혼잡하다고 판단하여 Cwnd를 1로 하고, 임계 지점의 크기를 반으로 줄인 후 다시 Slow Start 방식으로 Cwnd를 증가시킵니다.




Fast Retransmit( 빠른 재전송 ) & Fast Recovery( 빠른 회복 )

 

  • sliding window를 통해서 패킷을 송신하는 도중에 중간 패킷이 유실되어 수신자가 유실전 패킷에 대한 ACK를 3번 연속으로 보내게 될 경우 timeout을 기다리지 않고 유실된 패킷을 재전송합니다. 이러한 방식을 Fast Restransmit이라 하며, 이를 통해 TCP는 네트워크의 혼잡함을 인지하여 Cwnd를 1이 아닌 1/2로 줄이며 해당 지점을 임계 지점으로 설정합니다. 이후 ACK를 받을 때마다 1씩 최대 Awnd만큼 증가시키며 이를 Fast Recovery 라고 합니다.




3-way-handshake

 

 

  • 3-way-handshake는 TCP로 데이터를 송.수신하기 전에 1:1 연결하려는 PC간에 연결 정보를 교환함으로써 연결을 수립하는 과정을 말합니다.




3-way-handshake 과정

 

    1. 클라이언트는 connect() 함수를 호출하여 listen 상태의 서버에게 응답 패킷의 SYN 플래그를 활성화하고 임의의 Sequence Number를 담고 연결 정보와 같이 SYN 패킷을 송신합니다. 이 때 클라이언트의 연결 상태는 SYN-SENT 상태가 됩니다.

 

    1. SYN 패킷을 받은 서버는 수신 받은 패킷의 Sequence Number를 확인하고 응답하는 패킷에 SYN, ACK 플래그를 활성화하고 클라이언트의 Sequence Number에 1을 더하여 Acknowledgment Number를 셋팅합니다. 그리고 패킷에 임의의 Sequence Number와 연결정보와 같이 SYN/ACK 패킷을 송신합니다. 이 때 서버의 연결 상태는 SYN-RECEVED 상태가 됩니다.

 

    1. 서버의 응답을 받은 클라이언트는 ESTABLISHED 상태가 되어 연결 완료 상태가 되며, 서버에게 SYN-ACK 패킷에 담긴 Sequence Number에 1을 더하여 응답 패킷의 Acknowledgment Number를 셋팅하고 ACK 플래그를 활성화 후 응답을 합니다.

 

    1. 클라이언트의 응답을 받은 서버는 ESTABLISHED 상태가 되어 TCP 최종 연결이 완료됩니다.




3-way-handshake가 필요한 이유

 

  • 상호 연결정보를 교환할 때 얻은 Sequence Number, Acknowledgment Number, Window Size를 통해서 패킷이 몇 번째 패킷인지 그리고 패킷을 어디까지 수신 받았는지를 확인할 수 있습니다. 내가 송신한 패킷에 대한 ACK를 확인하여 상대방이 내가 송신한 패킷을 어디까지 수신 받았는지 확인하여 재전송 및 다음 패킷을 송신합니다.

    Window Size는 Sliding Window에 사용됩니다. Sliding Window는 응답이 오지 않아도 상대방의 Window Size 만큼 데이터를 송신하고 상대방은 수신 받은 여러개의 패킷에 대해서 하나의 ACK로 응답합니다. 이로 인해 ACK를 기다림으로써 발생되는 딜레이 및 네트워크 트래픽량을 줄일 수 있습니다.




4-way-handshake

 

 

  • 4-way-handshake는 1:1 연결된 TCP 세션간의 연결을 끊기 위한 과정을 말합니다.




4-way-handshake 과정

 

    1. 연결을 종료하려는 쪽이 close() 함수를 호출하여 FIN 플래그가 활성화된 패킷을 상대방에게 송신하며 이때 연결 상태는 FIN_WAIT_1 상태가 됩니다.

 

    1. FIN 패킷을 수신받은 쪽은 FIN 패킷의 Sequence Number에 1을 더하여 Acknowledgment Number에 셋팅하여 ACK 패킷으로 응답하며 이때 연결 상태는 CLOSE_WAIT 상태가 됩니다.

 

    1. FIN 패킷에 대한 ACK를 받은쪽은 FIN_WAIT_2 연결 상태가 되며, 상대방이 FIN 패킷을 송신하기만을 기다립니다.

 

    1. CLOSE_WAIT 상태에서 close() 함수를 호출하면 상대방에게 FIN 패킷을 송신하며 연결 상태는 LAST_ACK 상태가 됩니다.

 

    1. FIN_WAIT_2 상태에서 FIN 패킷을 받은쪽은 FIN 패킷의 Sequence Number에 1을 더하여 Acknowledgment Number에 셋팅하여 ACK 패킷으로 상대방에게 응답 후 연결 상태는 TIME_WAIT 상태가 됩니다.

 

    1. LAST_ACK 상태에서 FIN에 대한 응답은 받으면 연결 상태가 CLOSED 상태가 되어 TCP 연결이 종료됩니다.




4-way-handshake가 필요한 이유

 

  • 4-way-handshake 연결 종료 절차를 통해 상호 세션을 정리하는 과정을 수행할 수 있습니다. 하지만, FIN 패킷을 처음으로 보내는 PC는 TIME_WAIT이 남아 해당 IP에 대한 PORT를 한동안 사용할 수 없게 됩니다.

    이러한 TIME_WAIT이 남는 이유는 연결 종료 후에 동일한 포트가 바로 재사용되어 새로운 세션이 수립되었을 때 이전에 연결되었었던 상대방이 송신한 패킷이 뒤늦게 수신되어 잘못 처리될 수 있는 확률이 있기 때문에 TIME_WAIT을 통해서 해당 포트가 재사용되지 않도록 합니다.

    하지만, TIME_WAIT이 없다 하더라도 위와 같은 불상사가 발생할 확률은 매우 희박합니다. 왜냐하면 TCP는 안전한 송.수신을 보장하기 때문에 Sequence Number와 Acknowledgment Number가 일치해야 처리할 수 있기 때문입니다.




블로킹 소켓 ( Blocking Socket )

 

  • 블로킹 소켓은 소켓 함수를 호출했을 때 현재 수행할 수 없다면 수행할 수 있을 때 까지 block 되는 소켓을 말합니다.




넌블로킹 소켓 ( Nonblocking Socket )

 

  • 넌블로킹 소켓은 소켓 함수를 호출했을 때 현재 수행할 수 없다면 블락되지 않고 error를 return 하는 소켓을 말합니다.




블로킹 소켓과 넌블로킹 소켓 함수의 차이

 

accept()

 

블로킹 소켓

  • 현재 백로그 큐 ( Backlog Queue ) 에 연결 정보가 없다면 연결 정보가 Enqeue 될 때 까지 블락됩니다.

 

넌블로킹 소켓

  • 현재 백로그 큐 ( Backlog Queue ) 에 연결 정보가 없다면 INVALID_SOCKET 을 return 하며 WSAGetLastError(); 를 호출할 경우 WSAEWOULDBLOCK 이 return 됩니다.




connect()

 

블로킹 소켓

  • SYN 패킷을 보낸 후 상대방으로부터 응답이 올 경우 return 됩니다.

 

넌블로킹 소켓

  • SYN 패킷을 보낸 직후 바로 SOCKET_ERROR를 return 하며 WSAGetLastError(); 를 호출할 경우 WSAEWOULDBLOCK 을 return 합니다.




send()

 

블로킹 소켓

  • 소켓 송신 버퍼의 남은 공간이 송신하려는 데이터 크기보다 부족할 경우 소켓 송신 버퍼의 공간이 확보될 때 까지 블락됩니다.

 

넌블로킹 소켓

  • 소켓 송신 버퍼의 남은 공간이 송신하려는 데이터 크기보다 부족할 경우 남은 공간만큼 복사 후 소켓 송신 버퍼에 복사한 크기만큼 정수 형태로 return 합니다.




recv()

 

블로킹 소켓

  • 소켓 수신 버퍼의 수신된 데이터가 1byte 라도 없으면 소켓 수신 버퍼에 수신 데이터가 복사될 때 까지 블락됩니다.

 

넌블로킹 소켓

  • 소켓 수신 버퍼의 수신된 데이터가 1byte 라도 없으면 SOCKET_ERROR 를 return 하고 WSAGetLastError(); 를 호출했을 때 WSAEWOULDBLOCK 을 return 합니다.

+ Recent posts