4계층: 전송 계층
특징
데이터를 작은 패킷 단위로 분할하여 정상적으로 잘 보내지는지 확인한다.
하나의 통신이 회선 전체를 점유하지 않고 동시에 여러 단말이 통신하기 위한 목적으로 데이터를 분할해 보낸다.
패킷 분할 시 패킷 헤더에 보내는 순서와 받는 순서를 적어 통신하므로 , 패킷이 유실되면 재전송을 요청하고 패킷 순서가 바뀌면 이를 바로잡아 주는 역할을 한다.
보내는 순서는 Sequence Number, 받는 순서는 ACK 번호로 표현된다.
세그먼트 헤더에는 포트/소켓 주소가 포함된다.
일반적으로 TCP/IP 에서는 클라이언트용 프로그램과 서버용 프로그램을 별도로 개발하기 때문에 출발지/도착지 포트 번호가 중요하다.
일반적인 프로토콜이 사용되는 서버 포트는 IANA에 등록되어 있으며 1023번 이하의 포트를 사용하게 된다. HTTP 는 TCP 80, HTTPS는 TCP 443, SMTP는 TCP 25 로 통신하게 된다.
기능
종단간 (End to End) 데이터 통신 보장, 흐름 제어와 오류 제어 등을 통해 데이터 통신을 보장한다.
지연에 따른 왜곡 및 대역폭 부족 문제를 해결한다.
동시에 여러 개의 논리적 연결을 지원한다.
사용자 데이터 분할과 재조립을 통해 과부하를 예방한다.
TCP, UDP 프로토콜이 이 계층에 해당한다.
TCP
신뢰할 수 없는 공용망에서도 정보유실 없는 통신을 보장하기 위해 세션을 안전하게 연결하고 데이터를 분할하고 분할된 패킷이 잘 전송되었는지 확인할 수 있다.
각 패킷에 순서를 나타내기 위해 Sequence Number를 부여하고, 잘 전송되었는지에 대한 응답 번호를 나타내기 위해 Acknowledge Number를 부여한다. 두 번호를 통해 순서가 바뀌거나 중간에 패킷이 손실되었는지 파악할 수 있다.
한 번에 얼마나 보내야 할 지에 대한 Window Size를 고려해 통신한다.
3-Way Handshake
데이터 유실없이 안전한 통신을 위해 TCP 연결을 처음 맺을 때 목적지가 데이터를 받을 준비가 되었는지 확인한다.
서버는 서비스를 제공하기 위해 클라이언트의 접속을 받아들일 수 있는 LISTEN 상태로 대기한다.
클라이언트가 서버로 SYN 패킷을 송신하면, 서버는 SYN-ACK 패킷을 클라이언트에 전송한다. 이 때 서버 소켓의 상태는 SYN_RECEIVED가 된다.
SYN-ACK 패킷을 수신한 클라이언트는 서버로 ACK 패킷을 보내고 ESTABLISHED 상태가 된다.
서버도 ACK 패킷을 받으면 ESTABLISHED 상태가 된다.
TCP 헤더
패킷의 용도를 구분하기 위해 플래그 값을 넣어 통신한다. 플래그의 종류는 다음과 같으며, 패킷이 해당 목적일 때 1로 표시해 보낸다.
SYN : 연결 시작 용도로 사용한다.
ACK : ACK 번호가 유효할 때 사용한다. 초기 SYN 패킷 외에는 모두 기존 메시지에 대한 응답이 되므로 ACK 플래그가 1로 표기된다.
FIN : 데이터 전송을 마친 후 정상적으로 양방향 연결 종료 시 사용된다.
RST : 연결 강제 종료를 위해 일방적으로 연결 종료 시 사용된다.
URG : 긴급 데이터 용도로 사용한다.
PSH : 서버 측에서 전송할 데이터가 없거나 데이터를 버퍼링 없이 즉시 보낼 것을 지시할 때 사용한다.
ACK 번호
기본적으로 패킷을 수신하였을 때 ACK 번호를 담아 다음 패킷을 송신한다.
ACK 번호는
현재 시퀀스 번호 + 1
로 표기한다. 예를 들어 클라이언트는 시퀀스 번호 20이 담긴 패킷에 대해 ACK 번호가 21인 패킷을 보낸다. ACK을 받은 서버는 클라이언트에게 21이라는 시퀀스 번호를 담은 패킷을 보낸다.
송신자가 패킷을 전송하면 수신자는 이를 받은 후 잘 받았다는 의미를 담아 ACK 패킷을 송신자에 보낸다.
TCP는 ACK 번호를 확인하여 상대방이 패킷을 잘 받고 있는지 확인한 후 다음 패킷을 전송한다.
슬라이딩 윈도
패킷이 잘 전송되었는지 확인하기 위해 별도 패킷을 받는 것은 통신 시간을 늘리게 된다. 송신자와 수신자가 먼 거리에 떨어져 있으면 왕복 지연시간(Round Trip Time, RTT)이 늘어나므로 응답을 기다리는 시간이 더 길어진다.
따라서, 데이터를 보낼 때 패킷 하나만 보내지 않고 많은 패킷을 한꺼번에 보내고 응답을 하나만 받는다.
한 번에 데이터를 받을 수 있는 데이터 크기를 윈도우 사이즈라 하며, 슬라이딩 윈도우는 윈도우 사이즈를 조절하는 것을의미한다.
TCP 헤더에서 윈도우 사이즈는 최대 2^16이다. 하지만 점점 고속화되고 안정화되는 환경에 따라 64K 보다 큰 양의 패킷을 한꺼번에 보내려면, 뒤의 숫자를 무시하는 방법으로 증가시켜 사용할 수 있다.
데이터에 유실이 발생하면 윈도 사이즈를 절반으로 떨어뜨리고 정상적인 통신이 되는 경우, 서서히 하나씩 늘린다.
네트워크에 경합이 발생해 패킷 드롭이 생기면 작아진 윈도 사이즈로 인해 데이터 통신 속도가 느려져 회선을 제대로 사용하지 못할 수 있다. 경합을 피하기 위해 회선 속도를 증가시키거나, 버퍼가 큰 네트워크 장비를 사용하거나, TCP 최적화 솔루션을 사용해야 한다.
소켓 종료
종료를 원하는 Initiator에서 socket.close()와 같은 소켓 종료함수를 호출한다.
해당 소켓에 대한 권한이 tcp커널로 넘어가게 되고, 만약 소켓이 블로킹 소켓이면 위의 종료과정이 완전히 끝날때까지 블로킹되고, 논블로킹 소켓이면 EWOULDBLOCK을 리턴한다.
Initiator는 FIN_WAIT상태에 들어가고 상대호스트의 FIN 패킷을 기다린다.
FIN 메시지를 받은 Receiver는 받은 메시지에 대한 ACK 신호를 보내고 소켓 종료 함수를 호출해 FIN 패킷을 보내기 전까지 ClOSE_WAIT상태가 된다.
Receiver가 종료 함수를 호출하여 FIN을 보내면 Initiator는 받은 FIN에 대한 ACK를 보낸 후 일정 시간 동안 TIME_WAIT 상태가 된다.
TIME_WAIT은 자신이 보낸 ACK가 잘 도착했는지 확인 하기 위해 기다렸다 종료하는 유예 시간이다. 리눅스의 경우 90초 정도라고 하며, 자신이 보낸 ACK가 손실됬다면 상대는 다시 FIN을 보내게 되고 그에 따른 ACK를 보낼 수 있다.
만약 TIME_WAIT 상태인 포트로 접속하기 위해선 TIME_WAIT이 끝날때까지 기다려야 한다. 따라서 고정적인 포트에 바인딩하는 서버의 경우 에러가 나서 먼저 FIN을 보내고 TIME_WAIT에 걸렸을시 곧바로 서버를 재가동 시키지 못하는 불상사가 발생한다.
UDP
데이터 전송을 보장하지 않으므로 제한도니 용도로만 사용된다.
음성 데이터나 실시간 스트리밍과 같이 시간에 민감한 프로토콜이나 애플리케이션을 사용하는 경우나 사내 방송이나 증권 시세 데이터 전송에 사용되는 멀티캐스트처럼 단방향으로 다수의 단말과 통신해 응답을 받기 어려운 환경에서 주로 사용한다.
스트리밍 서비스의 경우 특히 데이터가 몇 개쯤 유실되는 것보다 재전송하기 위해 잠시 동영상이나 음성이 멈추는 것을 더 이상하게 느낄 것이다.
UDP는 TCP의 3방향 핸드셰이크 절차를 사용하지 않지만, 첫 데이터는 리소스 확보를 위해 인터럽트를 거는 용도로 사용되고 유실된다.
UDP 프로토콜을 사용하는 애플리케이션은 대부분 TCP 프로토콜로 먼저 연결 확립을 한 후 애플리케이션끼리 연결이 완료되면 실제 데이터만 UDP를 통해 전달한다.
장비
로드 밸런서
애플리케이션 구분자인 포트 번호와 패킷의 시퀀스 번호, ACK 번호를 이용해 부하를 분산한다.
대표 IP는 로드 밸런서가 갖고 로드 밸런서가 각 웹 서버로 패킷의 목적지 IP 주소를 변경해 보내준다.
방화벽
방화벽을 통과하는 패킷의 3,4계층 정보를 확인하여 패킷의 통과/차단 기능을 수행한다.
Last updated