리눅스에서 TCP 소켓과 LocalPort

아재발자·2024년 6월 1일
0

Linux

목록 보기
1/1

제가 2018년 1월부터 2021년 9월까지, 총 3년 9개월을 다녔던 회사에서 근무하면서 직접 경험한 내용을 바탕으로 공부하고 알게된 지식을 간단하게 정리하는 글입니다.


사전 지식

TCP/IP의 4-Tuple

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

LocalPort

TCP/IP 프로토콜 스택에서 Port 필드는 16비트의 크기를 가집니다. 하지만 0번 포트는 실제로 사용되지 않기 때문에 1~65535개의 범위를 갖습니다.

따라서 LocalPort는 우리가 일반적으로 알고있는 1~65535까지의 포트를 의미한다고 보시면 됩니다.

Socket

Unix 혹은 Unix 계열의 운영체제(예: 리눅스)에서 Socket은 TCP/UDP 또는 unix 방식 등의 통신을 위해 생성된 File Descriptor를 의미합니다.

그렇기 때문에 File Descriptor 제한에 영향을 받습니다.


TCP 소켓과 LocalPort의 관계

Server

Server는 Client와 통신을 하기 위해 아래의 절차를 거칩니다.

  1. socket 생성
  2. socket에 IP 주소와 Port를 설정 (bind)
    이 단계에서 Server는 생성된 socket에 INADDR_ANY(0.0.0.0)와 지정된 LocalPort 정보를 설정합니다.

    만약 bind 하려는 Port가 이미 사용중이라면 에러가 발생합니다.
  3. 수신 대기 (listen)
  4. 연결 수락 (accept)
    이 단계에서 Server는 동시성, 병렬성, 독립성 등의 이유로 해당 Client와 1:1 통신을 위한 Socket을 새로 생성합니다.

Server는 TCP 통신을 위한 소켓 정보(Client 정보와 bind 된 LocalPort)를 이미 알기 때문에 bind 시점에서만 LocalPort를 소비하고, 연결을 수락(accept) 과정에서 생성되는 Socket은 LocalPort를 고갈시키지 않습니다.

Client

Client는 Server와 통신을 하기 위해 아래의 절차를 거칩니다.

  1. socket 생성
  2. 커널에게 LocalPort를 요청합니다.
    socket을 생성하는 시점의 Client는 Source Port을 알지 못합니다. 그렇기 때문에 Client는 커널에게 사용 가능한 LocalPort를 요청하여 배정받아야 합니다.
    이 단계에서 Client는 LocalPort를 소비하게 됩니다.
  3. socket에 Source IP, Port와 Destination IP, Port를 설정합니다.
  4. TCP 통신을 시작합니다. (connect)

Client는 Server와의 통신을 위해 고유한 LocalPort를 사용해야 하기 때문에 LocalPort와 Socket은 1:1 관계를 가집니다. 따라서 동시에 통신하는 TCP 소켓이 많아질 수록 소비하는 LocalPort도 많아집니다.

TIME_WAIT

Socket이 TIME_WAIT 상태를 가지면 일정 시간동안 LocalPort를 반환하지 않고 점유하기 때문에 TCP 소켓 생성이 잦은 Client는 LocalPort 고갈 또는 리소스 부족으로 장애가 발생할 수 있습니다.

TCP 통신에서 연결 종료 절차는 아래와 같습니다.

  1. 송신자가 수신자에게 FIN 메세지를 보냅니다.
  2. 수신자는 송신자에게 ACK 메세지를 보냅니다.
  3. 수신자는 송신자에게 FIN 메세지를 보냅니다.
  4. 송신자는 수신자에게 ACK 메세지를 보냅니다.

위 4번 단계에서 수신자는 송신자가 보낸 ACK 메세지를 받지 못하는 상황이 생길 수 있습니다.

이러한 문제를 해결하기 위해 송신자의 Socket은 TIME_WAIT 상태를 가지고 일정시간을 대기한 다음에 연결을 종료합니다.

profile
안녕하세요. 아재 개발자입니다. 공부한 내용을 기록하고 잘못된 부분에 대해서 조언을 받기 위해 velog를 시작했습니다. :)

0개의 댓글