Connecting
Chapter 02 TCP/IP Packet Transmission - 1 본문
Chapter 02 TCP/IP Packet Transmission - 1
프로토콜 스택에 대한 전반적인 내용을 습득합니다.
NIC통신 과정에 대해 살펴봅니다.
IP패킷 및 UDP 프로토콜을 이용한 송/수신 동작을 살펴봅니다.
프로토콜 스택은 역할이 서로 다른 몇 부분으로 나뉘어져 있습니다.
상위계층인 Application Layer(네트워크 애플리케이션)의 경우 브라우저, 웹 서버, 메일 서버 등의 프로그램이 해당됩니다.
애플리케이션 하위계층에는 Socket 라이브러리가 있으며 이 안에는 저번시간에 설명한 Resolver가 포함되어 있습니다.
다음 하위계층에 OS에 내부에 프로토콜 스택이 존재합니다.
프로토콜 스택의 윗부분에 TCP, UDP와 같이 데이터 송 수신을 담당하는 부분이 있습니다.
이는 애플리케이션에서 필요하는 데이터를 송수신하는 역할을 담당합니다.
IP의 경우 패킷이라는 데이터 형식을 통해서 상대방까지 데이터를 운반하는 역할을 담당하게 됩니다.
IP 안에는 ICMP(패킷을 전송할 때 발생하는 오류를 및 제어용 메시지를 통지하는 역할), ARP(IP 주소에 대응하는 MAC 주소를 조사할 때 사용)가 있습니다.
마지막의 존재하는 PHY 계층의 경우 NIC가 실제로 전기적인 신호로 케이블을 사용하여 데이터를 송수신하는 역할을 담당합니다.
소켓(Socket)의 실체
이제 소켓(Socket)에 대해서 알아보도록 하겠습니다.
프로토콜 스택 내부에는 제어정보를 기록하는 메모리 영역을 가지고 있으며, 여기에 통신 동작을 제어하기 위한 제어정보를 기록합니다.
상대방의 IP
포트번호
통신 동작 상태
Socket은 개념적인 부분이므로 이러한 제어정보를 기록한 메모리 영역이 소켓이라고 지칭할 수 있습니다.
프로토콜 스택은 이 정보를 활용하여 실질적으로 데이터를 송수신하기 위한 절차들이 이루어지며, Socket에 기록된 여러가지 제어 정보를 참조하여 다음 행위를 진행합니다.
실질적으로 통신이 이루어지기 위해서는 Socket을 만들어야 합니다.
프로토콜 스택은 의뢰받은 요청에 따라 Socket을 만들기 전에 메모리 영역을 할당하여 제어정보를 담을 공간을 확보합니다.
이후 Socket을 나타내는 디스크립터를 애플리케이션에게 전달하여, 다수의 Socket 중 어느 것을 가리키는지 알 수 있게 됩니다.
이렇게 디스크립터가 Socket을 가리키게 되면 모든 정보는 Socket에 기록되어 있기 때문에 상대방의 정보를 애플리케이션에서 일일히 통지받을 필요가 없습니다.
접속(Connection)
이더넷이나 통신회선은 항상 연결되어 있기 때문에 언제나 신호를 받을 수 있습니다.
하지만, Socket을 만든 직후에 애플리케이션에서 데이터 송신 의뢰가 오면, 메모리에 어떠한 정보도 기록되어 있지 않기 때문에 통신상대를 알 수 없습니다.
이러한 문제를 해결하기 위해 접속을 위해서는 통신 상대와의 제어 정보를 주고 받아 Socket에 필요한 정보를 기록하고 데이터 송수신이 가능한 상태로 만들어주는 작업이 필요합니다.
헤더 정보를 확인하면 좀 더 명확하게 알 수 있습니다.
전송하고자 하는 데이터가 TCP 영역에 도착하면, 송신처와 수신처의 포트번호를 기입합니다. 이를 통해 서버측과 클라Socket을 지정하는 첫번째 단계가 진행됩니다.
접속해야 하는 Socket을 확실하게 정해지게 되면 Sequence Number(SYN) 컨트롤 비트를 1로 만듭니다.
이렇게 만들어진 TCP 헤더는 IP에 전달하여 송신할 수 있도록 의뢰하는 작업이 이루어지고, 패킷이 정상적으로 서버에 도착했을 경우 서버의 TCP가 헤더정보를 조사하여 수신 포트번호에 해당하는 Socket을 찾아냅니다.
클라이언트와 마찬가지로 헤더를 설정하고 Acknowloedgment Number(ACK) 컨트롤 비트를 1로 만들로 전송합니다.
이는 어떠한 이유로 오류가 발생하여 패킷이 손실되어 수신받지 못하는 상황을 대비하기 위함입니다.
클라이언트가 이러한 정보를 정상적으로 수신받았다면, TCP 헤더를 조사하여 SYN 비트가 1인지 확인하고 접속을 완료하는 동시에 서버측으로 ACK 비트를 1로 설정하여 전송합니다.
이는 서버측에서 보낸 정보가 정상적으로 도착했다는 것을 서버에 알려주기 위함입니다.
이러한 동작이 완료되면 데이터를 송수신할 수 있는 상태가 되며, 커넥션이 완료되었다고 표현합니다.
데이터 송수신
프로토콜 스택은 받은 데이터를 바로 전송하지 않고 송신용 버퍼 메모리 영역에 저장하고, 애플리케이션이 다음 데이터를 건네주기를 기다립니다.
송신시 애플리케이션에서 건네주는 데이터의 길이는 애플리케이션의 종류나 만드는 방법에 따라 다르기 때문입니다.
또한 받은 데이터를 곧바로 보내게 되면 작은 데이터를 많이 보내게 되며, 이는 네트워크 이용 효율의 저하로 나타납니다.
네트워크에서 최대로 보낼 수 있는 패킷의 사이즈는 MTU를 기반으로 판단하며, 보통 1,500byte가 됩니다.
이 때, MTU 맨 앞 부분에는 헤더가 포함되어 있기 때문에 헤더를 제외한 부분이 하나의 패킷으로 전송할 수 있는 최대 길이 MSS(헤더를 제외하고 한 개의 패킷으로 운반할 수 있는 TCP의 데이터의 최대 길이)가 됩니다.
애플리케이션에서 데이터가 MSS를 초과하거나 MSS에 가까운 길이에 이르기까지 데이터를 저장하고 송신동작을 하면 길이 맞춰서 잘라서 보내기 때문에 이후 동작에 대해서는 신경쓰지 않아도 됩니다.
또 하나로 애플리케이션의 송신 속도가 느려지는 경우 MSS에 가깝게 데이터를 저장하면 지연시간이 발생하기 때문에 버퍼에 데이터가 모이지 않더라도 적당한 시간이 경과하면 패킷을 송신합니다.
TCP에는 송신한 패킷이 상대에게 올바르게 도착했는지 확인하고, 도착하지 않았을 경우 재송신하는 기능이 있습니다.
TCP에서 데이터를 분할할 시 조각이 통신 개시부터 따져서 몇 번째 바이트에 해당하는지 세어둡니다.
이 데이터 조각을 송신할 때 세어둔 값을 TCP 헤더에 기록하는데, 이것이 시퀀스 번호가 됩니다.
송신측에서는 패킷의 전체 길이에서 헤더의 길이를 빼면 데이터의 크기를 알 수 있으므로, 수신측에서는 이 방법에 따라 크기를 산출합니다.
이렇게 수신측에서 데이터가 누락되었는지 확인할 수 있으며, 누락값이 있을 경우 이전에 수신받은 데이터의 길이를 확인하여 TCP 헤더에 기록하여 송신측에 전송합니다.
이렇게 송신 -> 확인 -> 응답에 대한 동작은 수신 확인 응답이라고 하며, 송신측은 이것을 통해 상대가 어디까지 수신했는지를 알 수 있습니다.
시퀀스 번호는 난수를 바탕으로 산출되는데, 이는 고정값으로 사용할 경우 해킹을 할 수 있기 때문입니다.
따라서 초기값을 사전에 상대에게 알려주어야 하며, 이를 위해 SYN 제어비트를 1로 설정하여 초기값을 통지합니다.
이러한 TCP의 특성 덕분에 네트워크의 오류가 발생하더라도, 오류를 검출하여 회복할 수 있습니다.
단, 통신 도중에 케이블이 분리되거나, 서버가 다운되는 등의 이유로 TCP가 해결할 수 없는 물리적인 이유로 인해서 통신이 불가능한 경우에도 계속해서 패킷을 전송하면 문제가 발생하기 때문에 응답이 없을 경우 회복 불가능이라고 판단하고, 애플리케이션에 오류를 통지합니다.
패킷 왕복시간을 통한 대기시간 계산
네트워크가 혼잡하여 정채가 일어나면 ACK 번호가 돌아오는 것이 지연되기 때문에 이것을 예측하여 적절한 대기시간을 설정해야 합니다. 이 대기시간을 타임아웃 값이라고 합니다.
하지만 이러한 대기시간은 서버와의 거리, 네트워크 혼잡 등 다양한 이유로 인해서 달라질 수 있기 때문에 대기시간을 일정한 값으로 설정하는 것은 적절하지 않습니다.
이러한 문제를 해결하기 위해서 TCP는 ACK 번호가 돌아오는 시간을 기준으로 동적으로 대기시간을 변경합니다.
이를 통해 데이터 송수신이 이루어 지는 동안 ACK가 지연되면 대기 시간을 지연시키고, ACK가 바로 들어오면 대기 시간을 짧게 설정합니다.
윈도우 제어
한개의 패킷을 보내고 ACK 번호를 기다리는 방법은 단순하지만, 그 시간동안 아무것도 하지 않는건 시간낭비입니다.
따라서 window congestion을 통해서 한 개의 패킷을 보내고 ACK 번호를 기다리지 않고 차례대로 복수의 패킷을 전송하는 방법을 사용합니다.
단, ACK 번호를 기다리지 않고 차례로 패킷을 보내면 수신측의 능력을 초과하여 패킷을 보내는 사태가 일어날 수 있습니다.
TCP는 패킷을 수신하면 버퍼에 내용을 저장하는데, 수신측에서 ACK 번호를 계산하거나, 여러 패킷을 복원하여 애플리케이션으로 전달해야 합니다.
이때, 처리가 끝나지 않은 상태에서 계속해서 데이터가 들어오면 수신버퍼에 데이터가 가득차고, 이후에 들어오는 데이터는 사라지기 때문에 오류가 발생하게 됩니다.
이러한 문제를 해결하기 위해서 수신측에서 자신의 버퍼의 용량을 알려주고, 송신측은 데이터를 전송함에 있어서 수신측의 메모리 영역을 계산하게 됩니다.
수신측의 버퍼메모리의 공간이 없으면, 송신을 중단하고, 수신측에서 데이터를 처리한 다음에 비어진 영역만큼의 공간을 송신측의 통보함으로서 수신측의 능력을 초과하여 데이터를 보내는 일이 없도록 합니다.
이렇게 수신 가능한 데이터 양의 최대값을 윈도우 사이즈라고 하며, TCP를 조정하는 매개변수의 하나입니다.
수신측에서 ACK번호를 바로 통지하는 것은 수신측에서 송신측에 보내는 패킷이 많이지기 때문에 효율성이 떨어집니다.
수신한 데이터의 끝이 어디인지를 알리는 것이 ACK의 역할 이므로 ACK 번호 통지가 연속적으로 일어나면 최후의 것만 통지하고 도중의 것은 생략하여 패킷을 줄일 수 있습니다.
TCP 연결 종료
송수신을 종료한다는 것은 애플리케이션이 송신해야 하는 데이터를 전부 송신 완료했다고 판단했을 때 입니다.
따라서 데이터를 보낸 쪽에서 연결을 종료하기 위해서 TCP헤더에 FIN을 1로 설정한 패킷을 전송합니다.
이를 수신한 클라이언트는 정상적으로 패킷을 수신했다는 ACK를 반송하여 종료동작이 완료됩니다.
이러한 동작이 정상적으로 이루어지기 위해서 소켓을 바로 종료하지 않고 보통 몇 분 정도의 시간이 지다고 말소하게 됩니다.
'네트워크 ' 카테고리의 다른 글
QUIC (Quick UDP Internet Connection) 개념 (2) | 2018.12.02 |
---|---|
MPLS와 SD-WAN 이해하기 (0) | 2018.11.30 |
Chapter 01 HTTP와 DNS 동작원리 (13) | 2018.10.28 |
FreeNAS 설치 및 운영하기 (0) | 2018.06.19 |
2017년 이동통신 프로토콜 학습자료 2 (0) | 2018.06.03 |