[Socket] 소켓 기본 개념과 TCP 이해
소켓(Socket) 이란?
소켓(Socket)은 네트워크 상에서 데이터를 주고받기 위한 양쪽 끝점(endpoint)이다. 쉽게 말해, 인터넷을 통해 컴퓨터끼리 대화를 나누려면 서로 연결되는 "통로"가 필요한데, 그 통로가 바로 소켓이다. 소켓을 전화 주문에 비유해보겠다.
- 음식점(서버) : 여러 손님(클라이언트)에게 음식을 판매하는 곳
- 손님(클라이언트) : 음식점에 전화해서 음식을 주문하는 사람
- 전화(소켓) : 주문을 주고받기 위한 통로
- 전화번호(IP + 포트) : 해당 음식점에 전화를 걸기 위한 주소
손님(클라이언트)은 음식점(서버)에 전화를 걸어(소켓 연결) 주문을 하고(데이터 전송) 음식점에서 주문을 받아 응답하는 형식이다.
아래에서 조금 더 자세하게 소켓에 대해 살펴보겠다.
소켓의 기본 개념
소켓은 기본적으로 (프로토콜, IP 주소, 포트 번호) 이렇게 3가지로 정의된다.
- 프로토콜 : 데이터를 보내는 방식(TCP : 신뢰성 / UDP : 빠름)
- IP 주소 : 어느 컴퓨터(서버)와 연결할지 나타냄
- 포트 번호 : 컴퓨터 안에서 어떤 서비스와 연결할지 나타냄
이때 소켓은 크게 두 가지 방식으로 나뉘는데, TCP 와 UDP 방식이다. TCP는 스트림을 사용하고, UDP는 데이터그램을 사용하는데, 이는 OSI 7계층 중, 전송 계층에서 동작하는 프로토콜이다.
1. TCP (스트림 소켓)
- 연결 지향적 : 연결을 먼저 맺고 데이터를 주고 받음
- 신뢰성 : 데이터 순서를 보장하고, 손실된 경우 재전송을 통해 데이터 무결성 보장
- 흐름 제어 : 데이터 전송 속도를 조절함
- 혼잡 제어 : 네트워크 혼잡 방지를 위해 데이터 전송 속도 조절
- Ex) HTTP, FTP, SSH
2. UDP (데이터그램 소켓)
- 비연결 지향적 : 데이터를 바로 보내고 끝
- 속도가 빠르지만, 신뢰성이 낮음(데이터 손실 가능)
- Ex) 온라인 게임, 스트리밍
소켓의 통신 과정
TCP 소켓 통신의 과정과 전체적인 흐름을 쉽게 이해해보자. 위에서 말했듯이 TCP 통신의 특징은 연결 지향적이라는 것이다. 우선, 이해하기 쉽게 전체적인 흐름을 쉽게 나타내보겠다.
- 서버가 문을 연다 -> socket(), bind(), listen()
- 클라이언트가 문을 두드린다 -> socket(), connect()
- 서버가 문을 열어준다 -> accept()
- 데이터를 주고 받는다 -> send(), recv()
- 문을 닫고 연결을 종료한다 -> close()
이와 같이 TCP는 클라이언트와 서버간의 연결을 맺고, 데이터를 주고 받은 후 연결을 종료하는 방식으로 동작한다.
아래 그림을 참고하여 시간 순서에 따른 흐름을 정리해보겠다. (출처 : 구글링, 누구인지 모르겠지만 최초 제작 해주신 분 감사합니다)

1. 서버 측 준비
서버는 클라이언트의 요청을 받을 준비를 한다.
(서버) socket() -> bind() -> listen()
- socket() : 소켓을 생성
- bind(IP, Port) : IP 주소와 포트를 설정
- listen() : 클라이언트의 연결 요청을 기다림(대기 상태)
2. 클라이언트 연결 요청
클라이언트는 서버에 연결하고자 요청함. 실제로 데이터 송수신이 일어나는 것은 클라이언트 소켓이다.
(클라이언트) socket() -> connect()
- socket() : 소켓을 생성
- connect(IP, Port) : 서버에 설정된 IP 주소와 포트에 연결 요청 (SYN 패킷 전송)
3. TCP 3-way Handshake (연결 과정)
TCP는 신뢰성을 보장하기 위해 3단계 과정을 거쳐 연결을 맺는다.
(서버) accept() -> (3-way Handshake 진행)
- accept() : 클라이언트의 요청 수락 (3-way Handshake)

| 단계 | 클라이언트 | 서버 | 설명 |
| 1단계 (SYN) | SYN 전송 | 대기중 | 클라이언트가 연결 요청 (SYN 패킷) |
| 2단계 (SYN-ACK) | 대기중 | SYN-ACK 응답 | 서버가 요청 수락 및 응답 (SYN-ACK 패킷) |
| 3단계 (ACK) | ACK 전송 | 연결 확립 | 클라이언트가 응답 (ACK), 연결 완료 |
4. 데이터 송수신
연결이 완료되면, 서버와 클라이언트는 데이터를 주고받는다.
(서버 & 클라이언트) send() <-> recv()
- 클라이언트 -> 서버 : send() 데이터 전송
- 서버 -> 클라이언트 : recv() 로 데이터 수신 및 처리
- 서버 -> 클라이언트 : send() 로 응답 전송
- 클라이언트 -> 서버 : recv() 로 응답 수신
위 과정을 반복하며 데이터를 송 수신 한다.
5. 연결 종료 (4-way Handshake)
서버와 클라이언트가 모두 close()를 호출하면 연결을 종료한다. 연결을 종료할 때는 4단계를 거쳐 안전하게 종료됨
(서버 & 클라이언트) close()
| 단계 | 클라이언트 | 서버 | 설명 |
| 1단계 (FIN) | FIN 전송 | 대기중 | 클라이언트가 연결 종료 요청 (FIN) |
| 2단계 (ACK) | 대기중 | ACK 응답 | 서버가 연결 종료 요청 수락 (ACK) |
| 3단계 (FIN) | 대기중 | FIN 전송 | 서버도 종료 요청 (FIN) |
| 4단계 (ACK) | ACK 응답 | 종료 완료 | 클라이언트가 응답 (ACK), 연결 완전히 종료 |
정리
[서버]
- socket() : 소켓 생성
- bind(IP, Port) : IP주소와 포트번호 설정
- listen() : 클라이언트 연결 요청까지 대기
- accept() : 클라이언트 연결 요청 수락 (3-way Handshake 진행)
- recv() / send() : 데이터 주고받음
- close() : 연결 종료 (4-way Handshake)
[클라이언트]
- socket() : 소켓 생성
- connect(IP, Port) : 서버에 연결 요청 (3-way Handshake 진행)
- send() / recv() : 데이터 주고받음
- close() : 연결 종료 (4-way Handshake)