제가 2018년 1월부터 2021년 9월까지, 총 3년 9개월을 다녔던 회사에서 근무하면서 직접 경험한 내용을 바탕으로 공부하고 알게된 지식을 간단하게 정리하는 글입니다.
TCP 통신을 위해 사용되는 소켓은 Source IP
, Source Port
, Destination IP
, Destination Port
4개의 Tuple을 기준으로 생성이 됩니다.
예를 들어 MySQL 서버에 연결을 한다고 가정하면, TCP 통신을 위한 소켓의 Header는 아래와 같이 구성됩니다.
Source IP: Client IP
Source Port: Client Port
Destination IP: MySQL 서버 IP
Destination Port: 3306
TCP/IP 프로토콜 스택에서 Port 필드는 16비트의 크기를 가집니다. 하지만 0번 포트는 실제로 사용되지 않기 때문에 1~65535개의 범위를 갖습니다.
따라서 LocalPort는 우리가 일반적으로 알고있는 1~65535까지의 포트를 의미한다고 보시면 됩니다.
Unix 혹은 Unix 계열의 운영체제(예: 리눅스)에서 Socket은 TCP/UDP 또는 unix 방식 등의 통신을 위해 생성된 File Descriptor를 의미합니다.
그렇기 때문에 File Descriptor 제한에 영향을 받습니다.
Server는 Client와 통신을 하기 위해 아래의 절차를 거칩니다.
Server는 TCP 통신을 위한 소켓 정보(Client 정보와 bind 된 LocalPort)를 이미 알기 때문에 bind 시점에서만 LocalPort를 소비하고, 연결을 수락(accept) 과정에서 생성되는 Socket은 LocalPort를 고갈시키지 않습니다.
Client는 Server와 통신을 하기 위해 아래의 절차를 거칩니다.
Source Port
을 알지 못합니다. 그렇기 때문에 Client는 커널에게 사용 가능한 LocalPort를 요청하여 배정받아야 합니다.Client는 Server와의 통신을 위해 고유한 LocalPort를 사용해야 하기 때문에 LocalPort와 Socket은 1:1 관계를 가집니다. 따라서 동시에 통신하는 TCP 소켓이 많아질 수록 소비하는 LocalPort도 많아집니다.
Socket이
TIME_WAIT
상태를 가지면 일정 시간동안 LocalPort를 반환하지 않고 점유하기 때문에 TCP 소켓 생성이 잦은 Client는 LocalPort 고갈 또는 리소스 부족으로 장애가 발생할 수 있습니다.
TCP 통신에서 연결 종료 절차는 아래와 같습니다.
위 4번 단계에서 수신자는 송신자가 보낸 ACK 메세지를 받지 못하는 상황이 생길 수 있습니다.
이러한 문제를 해결하기 위해 송신자의 Socket은 TIME_WAIT
상태를 가지고 일정시간을 대기한 다음에 연결을 종료합니다.