CS를 또! 공부하다보니 TCP/IP에 대해 작성한 것을 봤고, 문득 궁금한 점이 생겼습니다. 패킷은 실제로 어떻게 생겼을까..?
사실 이론 공부를 하고, 네트워크 수업에서 TCP의 구조는 자주 봐왔으나 (심지어 와이어샤크로 보여주기까지 했었던 걸로 기억함) 역시나 내가하지 않으면 기억나지 않는법인거 같습니다.
오늘은 간단한 TCP/IP의 연결 과정을 한번 봐볼까 합니다.
TCP 과정을 직접 보기 위해선 간단한 준비물이 필요합니다.
사실 간단한 프로그램이라 인텔리제이없이 CLI 환경에서 자바를 실행해도 무방하나, 있는김에 사용했습니다. 코드는 간단합니다.
import java.io.*;
import java.net.*;
public class TCPServer {
public static void main(String[] args) {
int port = 5000; // 사용할 포트 번호
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("서버: 포트 " + port + "에서 대기 중...");
while (true) {
Socket clientSocket = serverSocket.accept();
System.out.println("서버: 클라이언트 연결됨: " + clientSocket.getRemoteSocketAddress());
// 간단하게 클라이언트에게 메시지 전송
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
out.println("안녕하세요, 클라이언트님!");
// 클라이언트와의 통신 후 소켓 종료
clientSocket.close();
System.out.println("서버: 클라이언트 연결 종료됨: " + clientSocket.getRemoteSocketAddress());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
import java.net.*;
public class TCPClient {
public static void main(String[] args) {
String serverAddress = "127.0.0.1"; // 로컬호스트
int port = 5000;
try (Socket socket = new Socket(serverAddress, port)) {
System.out.println("클라이언트: 서버에 연결됨: " + socket.getRemoteSocketAddress());
// 서버로부터 메시지 읽기
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String message = in.readLine();
System.out.println("클라이언트: 서버로부터 메시지 받음: " + message);
// 연결 종료 후 소켓이 자동으로 close()됨 (try-with-resources 사용)
System.out.println("클라이언트: 연결 종료");
} catch (IOException e) {
e.printStackTrace();
}
}
}
순서에 맞게 서버를 먼저 실행시켜 주시면 됩니다. 서버는 5000 포트에 소켓을 열고, 리스닝 상태로 대기합니다. 클라이언트 또한 소켓을 열고 서버의 포트에 연결을 시도합니다. 서버와 클라이언트가 연결이 된다면 이후 해당 소켓에게 getOutputStream 을 통해 println 메세지를 전달합니다. 클라이언트 측은 이를 받아 화면에 출력 후 종료합니다.
이로서 간단한 로직은 완료가 되었습니다. 이 과정에서 서버는 클라이언트와 연결을 맺고(3-way-handshake) 끊는 과정(4-way-handshake)을 순차적으로 진행합니다. 이를 와이어 샤크를 통해 확인해보겠습니다.

위의 과정을 모두 와이어샤크를 통해 캡쳐한 사진입니다.
순서대로 보겠습니다!
이처럼 일련의 과정 이후 TCP 연결이 완료됩니다.
도중에 클라이언트가 비정상 종료를 하게 된다면 FIN 패킷을 보내지 못하기 때문에 서버는 FIN을 기다리는 상태(TIME_WAIT 또는 CLOSE_WAIT)에 들어가게 됩니다.
하지만 TCP Keep-Alive 또는 Timeout 설정에 의해 연결이 자동 종료됩니다.
오늘도 짧게 TCP를 직접 실행해봤습니다. 워낙 중요하고, 자주 나오는 개념이라 알고 있었지만 이렇게 와이어샤크와 간단한 프로그램을 통해 확인한 것은 처음이라 흥미로웠습니다.
음... 그럼 이만..
