오늘은 TCP와 UDP에 대해 알아보자!
TCP UDP는 TCP/IP 프로토콜 모델에서 전송 계층에 해당한다. 전송(트랜스포트) 계층은 응용 프로그램과 네트워크 사이에서 중재하는 역할을 맡고 있으며, 애플리케이션 프로세스들 간의 논리적 통신(logical communication)을 제공한다.
UDP(사용자 데이터그램 프로토콜)
비연결형, 신뢰성 없는 전송 프로토콜
UDP는 최소한의 오버헤드만 사용하는 매우 간단한 프로토콜이다. 작은 메시지를 보내거나 또한 신뢰성을 고려하지 않는 프로세스는 UDP를 사용할 수 있다. UDP를 사용하여 작은 메시지를 전송하는 것이 TCP를 사용하는 경우보다 송신자와 수신자 간의 상호 대화가 훨씬 적다. handshaking이 일어나지 않으며, congestion control을 제공하지 않는다.
UDP는 어떻게 이루어져 있을까?
아래에 첫번째 그림을 살펴 보면 IP datagram에 UDP datagram이 포함되어있는 걸 볼 수 있다.
두 번째 그림은 UDP Header에 포함되어 있는 내용 4가지와 data를 포함시킨 그림이다.
발신지/목적지 포트 번호는 말 그대로 발신지/목적지 호스트 상에서 수행되는 프로세스에 의해 사용되는 포트번호를 의미하고,
길이와 관련한 16비트 필드는 헤더와 데이터를 합한 사용자 데이터그램의 전체 길이를 나타낸다.
checksum은 검사합으로, 헤더와 데이터를 모두 포함한 사용자 데이터그램 전체에 대한 오류를 탐지하기 위해 사용된다. checksum은 간단하게만 설명하면, TCP가 아닌 UDP에 속한 패킷이라는 것을 확인해 주는 역할을 하기도 하고, 잘못된 호스트로 전달되지 않도록 방지하는 역할을 하기도 한다. Transport 층에서 담당하는 오류 제어를 엿볼 수 있는 부분이다.
TCP(전송제어 프로토콜)
연결형, 신뢰성이 강한, 스트림 기반의 프로토콜
UDP는 정해진 길이의 메시지에 헤더를 붙여 IP에 전달하는 프로토콜이었다면, TCP는 스트림기반의 프로토콜로, 데이터가 전체적으로 정확하게 전송됨을 보장하기 위해 세그먼트 단위로 분할하고, 각각의 세그먼트에 대해 확인 응답 및 재전송 기능을 제공한다. 이로써 데이터가 순서대로 들어오고, 손실 없이 신뢰성을 보장할 수 있다. handshaking이 일어나며, congestion control을 제공해준다.
아래 그림으로 TCP의 well known 포트를 확인할 수 있다. 꽤 많은 서비스를 차지하고 있다.
TCP의 세그먼트 형식
UDP에 비해 세그먼트(헤더)의 형식이 매우 복잡하다. 똑같이 발신지/목적지 포트 주소를 가지고 있고,
순서 번호(sequence number)로 데이터들이 순서대로 도달할 수 있도록 하여 신뢰성 있는 연결을 보장한다.
확인응답 번호(acknowledgement number)를 통해 상대방 노드로부터 데이터를 확실하게 수신하였는지 확인할 수 있다.
창 크기(window size)는 바이트 형태의 송신 TCP 창을 의미하며 이 창의 크기는 수신 측에 의해서 결정된다.
검사합(checksum) UDP와 같은 기능을 하며 TCP에서 검사합은 필수 사항이다.
긴급 포인터(urgent pointer) 긴급 플래그가 1로 되어 있는 경우 긴급 데이터를 포함하고 있음을 의미한다.
대충 봐도 신뢰성이 높을 수 밖에 없는 구조이다..
다양한 특징으로 TCP와 UDP를 직접 비교해보자.
- 다중화↑와 역다중화↓(=)
TCP/IP 프로토콜을 수행하고 있는 호스트에서는 UDP/TCP는 하나지만 UDP/TCP 서비스를 사용하기를 원하는 프로세스는 여러개일 수 있다. 이러한 상황을 위해 1대다 다대1 로 서비스를 보내거나/받을 수 있다. - 캡슐화와 역캡슐화(=)
UDP/TCP 캡슐화 - 받은 데이터에 UDP/TCP header를 붙여 IP data로 만들어 네트워크층에 전달
UDP/TCP 역캡슐화 - IP data에서 IP header를 떼어낸 값을 받아 UDP header를 떼어내 Message만 application에 전달 - 혼잡 제어(≠)
UDP에서는 checksum이외에 혼잡제어를 따로 더 수행하지 않지만, TCP는 높은 신뢰성을 위해 기능이 더 추가되어 있다. 전송되는 데이터 양 또한 수신 측에 의해 조절될 뿐만 아니라 네트워크의 혼잡 정도에 의해서도 고려되어 혼잡이 제어된다. - 구현 방법(≠)
UDP는 queue 방식으로 이루어져 있다.
반면 TCP는 연결형 서비스로 전이중 방식으로 데이터를 전송한다. 큐 대기 방식이 아니라 동시에 세그먼트를 주고받는 데이터 교환 방식이라고 생각하면 쉽다. 대부분의 구현에서는 3-방향 핸드셰이크 방식을 사용한다. - 역다중화 방법 connectionless(UDP) VS connection oriented(TCP)
- UDP(connectionless)
UDP socket은 (목적지 IP와 목적지 port#)로 구성된 두 요소로 된 집합에 의해 식별된다.
UDP가 segment를 전달하는 과정
-> Segment의 dest port#를 검사한다. -> Segment를 적절한 socket으로 전달한다. -> 이 때 두 개의 UDP segment들이 출발지 IP나 port#가 둘 다 다르거나 둘 중 하나가 다르더라도 동일한 목적지 IP와 port#를 가지면 동일한 socket을 통해 애플리케이션 층에 전달된다. - TCP(connection oriented)
(출발지 IP, 출발지 port #, 목적지 IP, 목적지 port#) 4개로 구성된 집합에 의해 식별된다.
UDP와는 다르게, 각각의 다른 요청마다 다른 socket을 이용한다. 그리고 이 안에서는 threaded server가 존재해 한 프로세스 안에 여러 개의 실행 코드들이 실행될 수 있다.
- UDP(connectionless)
- checksum
TCP UDP 사용기준
아래부터는 TCP 통신에 대해 수업시간에 조금 디테일하게 다룬 내용이다.
TCP sender (simplified)
우선 TCP에서는 C-S 구조로, 클라이언트와 서버 모두 sender가 될 수 있다는 것을 상기하자. 또한 SR 방식처럼 송신자/수신자 모두 buffer를 가지고 있을 수 있다. 이 buffer는 스펙이 따로 정해진 게 아니라 구현자 맘이다(?)
sender 측에서 발생할 수 있는 이벤트는 그림과 같이 3가지가 있을 수 있다.
- 애플리케이션 계층으로부터 데이터를 받는 경우
이 때에는 세그먼트를 만들고, seq 번호에 NextSeqNum을 헤더에 넣어준다.
그 후 NextSeqNum을 현재 보내는 데이터의 크기만큼 증가시켜준다. --> 이는 이후 receiver에서 보내는 ACKnum이 된다. 그리고 만약 현재 가동 중인 타이머가 없다면 타이머를 가동한다. - 네트워크 계층으로부터 ACK를 받는 경우
SendBase와 들어온 ACK 필드의 값(y)를 비교하여 만약 y값이 더 크다면 SendBase 값을 y로 갱신시킨다. ACK는 누적해서 쌓이게 되므로 ACK로 83이 왔다면 이 이전 데이터는 모두 전송이 안전하게 수행되었음을 의미한다. 그리고 현재 아직 ACK를 받지 못한 세그먼트가 있다면 타이머를 가동하고, 없다면 타이머를 종료시킨다. - 타임아웃이 발생하는 경우
ack를 받지 못한 가장 작은 seq 넘버만 보낸다(GBN과의 차이). 그 뒤에 ack를 받지 못하면 또 거기에서 타임아웃이 날 것이므로 상관없다!
receiver에서는 ack를 누적으로 보낸다. 아래의 두 번째 그림과 같이 만약 timeout으로 인해 데이터가 늦게 와서, 기존에 보냈던 데이터들을 다시 보낸 상황일지라도 HostB에서는 받은 데이터까지, 즉 120에 대한 ACK를 보내게 된다.
fast retransmit
Timer를 사용하지 않고도 3번의 duplicated ack(ack=100 ack=100 ack=100)이 3번 일어나면 자동으로 빠르게 재전송을 하는 알고리즘 또한 사용하고 있다.
TCP의 RTT 를 이용하여 timeout 시간 정하기
TCP 연결관리 flow control
위 그림은 sender 측의 seq 공간을 표현한 것이다. 초록색은 밖으로 전송이 되었고 ack도 받은 상태, 노란색은 전송은 되었으나 ack를 받지 못한 상태이다. 위에서 볼 수 있듯 노란색, 즉 [last byte sent - last byte ACKed] 한 값은 현재 날아가고 있는(in-flight) 데이터의 크기를 의미한다. 이 값은 항상 rwnd보다 작도록 설계되어야 한다.
TCP connection Management
TCP: connection - 3-way HandShake
1. 클라이언트 측에서 SYN segment를 보낸다. 이 안에는 client initial seqnum(client_isn)를 준다.
2. 서버에서는 SYN을 받으면 SYNACK 세그먼트를 보낸다. 이 때 TCP 버퍼와 변수들을 할당한다. ACK은 받은 client_isn+1을 주세요~라고 보낸다. 이후 Server Initial Sequence Num을 보낸다. (server_isn)
3. 클라이언트는 SYNACK을 받으면 다시 ACK(server_isn+1)를 주고 여기에 TCP 버퍼와 변수들을 할당한다. 그리고 여기부턴 데이터를 같이 담아서 보낼 수 있다!
TCP: closing connection - 4-way HandShake
아래 그림에서 FIN에 해당하는 flag를 통해 소통할 수 있다. 이 때에는 SYNACK을 같이 보내지 않고 한 템포 쉬었다가 보내는 모습을 아래에서 확인할 수 있다. 이는 서버를 끝낼 때의 후속 작업들을 위해 (아직 보내지 않은 데이터들 다 보내고 ... 등)필요하다. 그리고 나서도 Timed_wait(대략 30초)라는 시간동안 대기를 한 후에 종료를 하는데, 이 이유는 마지막으로 보낸 메시지가 손실된 위험이 있기 때문에 마지막 메시지가 손실되었다면 서버측에서 재전송요청을 하게 되니 이동안 기다려주어야 한다.
'CS > 네트워크' 카테고리의 다른 글
[네트워크] 혼잡 제어 (0) | 2023.04.23 |
---|---|
[네트워크] 트랜스포트 계층 - 신뢰적인 데이터 전송 (RDT) (0) | 2023.04.22 |
[네트워크] 애플리케이션 계층-4 (0) | 2023.04.21 |
[네트워크] 애플리케이션 계층-3 (2) | 2023.04.17 |
[네트워크] 애플리케이션 계층-2 (0) | 2023.04.17 |