네트워크를 들여다보기
지금까지 우리가 만든 통신은 모두 눈에 보이지 않게 흘렀습니다. 소켓 안에서 무슨 일이 벌어지는지는 print로 찍어 보는 게 전부였습니다. 하지만 진짜 문제가 생겼을 때, 예를 들어 데이터가 안 가거나 연결이 이상하게 끊길 때는 통신 자체를 직접 들여다봐야 합니다. 이 장에서 네트워크를 눈으로 관찰하는 도구들을 배웁니다. 이 도구들은 소켓 프로그래머의 청진기이자 현미경입니다.
lsof로 소켓 들여다보기
가장 먼저 만날 도구는 lsof입니다. 이름은 list open files, 곧 열린 파일 목록이라는 뜻입니다. PART 01에서 소켓은 곧 파일이라고 배운 것을 떠올리세요. 소켓도 열린 파일의 하나이므로 lsof로 볼 수 있습니다.
서버를 띄워 둔 채로 특정 포트를 누가 듣고 있는지 물어봅니다.
# 파일: 터미널lsof -nP -iTCP:9080
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
Python 66456 jeongps 3u IPv4 ... 0t0 TCP 127.0.0.1:9080 (LISTEN)
많은 것을 알 수 있습니다. Python 프로그램이, 66456번 프로세스로, 127.0.0.1의 9080번 포트를 듣고 있습니다(LISTEN). 옵션 중 -n은 주소를 이름으로 바꾸지 말고 숫자 그대로 보여 달라는 뜻이고, -P는 포트도 숫자 그대로 보여 달라는 뜻입니다. 둘 다 빠르고 명확한 출력을 위한 것입니다.
여기서 FD 칸의 숫자 3을 눈여겨보세요. PART 01에서 배운 파일 디스크립터입니다. 이 서버 소켓이 3번 파일 디스크립터로 열려 있다는 뜻입니다. 소켓이 정말 파일처럼 번호를 부여받아 관리된다는 것을, 이 한 줄이 눈앞에서 증명합니다. "Address already in use" 같은 문제가 났을 때, lsof로 그 포트를 누가 붙들고 있는지 찾아내는 것이 첫걸음입니다.
tcpdump로 패킷 엿보기
lsof가 소켓의 상태를 본다면, tcpdump는 실제로 오가는 패킷을 엿봅니다. 네트워크를 흐르는 데이터를 가로채 보여 주는 도구입니다.
# 파일: 터미널sudo tcpdump -i lo0 -n port 9000
-i lo0은 루프백 인터페이스를 지켜보라는 뜻입니다. 우리 예제가 대부분 루프백을 쓰기 때문입니다. 리눅스에서는 루프백 이름이 lo인 경우가 많습니다. port 9000은 9000번 포트의 트래픽만 보겠다는 거름망입니다. 패킷을 가로채는 일은 권한이 필요하므로 sudo로 실행합니다.
이 상태에서 우리 에코 서버에 클라이언트를 붙이면, 3-way 핸드셰이크의 SYN과 ACK, 데이터 전송, 그리고 연결 종료가 패킷 단위로 줄줄이 찍힙니다. PART 02에서 글로만 배운 핸드셰이크가 실제로 일어나는 모습을 처음으로 눈으로 보게 됩니다. 통신이 이론대로 흐르는지 의심스러울 때, tcpdump만큼 확실한 증거는 없습니다.
Wireshark로 더 깊이 보기
tcpdump가 글자로 보여 준다면, Wireshark는 같은 일을 그래픽 화면으로 보여 줍니다. 패킷 하나를 클릭하면 각 계층의 헤더가 펼쳐지고, 어느 바이트가 무엇을 뜻하는지 색으로 구분해 줍니다. 한 연결의 데이터를 처음부터 끝까지 이어 붙여 보여 주는 기능도 있어, 우리 프로토콜이 실제로 어떻게 흐르는지 한눈에 따라갈 수 있습니다.
소켓 프로그래밍을 배울 때 Wireshark는 더없이 훌륭한 학습 도구입니다. 우리가 짠 코드가 만들어 내는 패킷을 직접 보면, 추상적이던 개념들이 손에 잡히는 실체가 됩니다. 네트워크를 깊이 이해하고 싶다면 "소설처럼 읽는 데이터통신과 컴퓨터 네트워크"에서 Wireshark를 본격적으로 다루니 함께 보기를 권합니다.
strace로 시스템 콜 추적하기
마지막 도구는 조금 다른 각도에서 봅니다. strace는 프로그램이 운영체제에게 어떤 부탁을 하는지, 곧 시스템 콜을 추적합니다. 리눅스의 도구이며, macOS에서는 dtruss가 비슷한 일을 합니다.
# 파일: 터미널 (리눅스)strace -e trace=network python3 echo_server.py
-e trace=network는 네트워크 관련 시스템 콜만 보겠다는 거름망입니다. 이 상태로 우리 서버를 실행하면, socket, bind, listen, accept, recv, send 같은 호출이 순서대로 화면에 찍힙니다. 우리가 Python이나 C로 부른 함수가, 그 아래에서 실제로 어떤 운영체제 시스템 콜로 이어지는지를 적나라하게 보여 줍니다. Python의 한 줄이 어떤 시스템 콜이 되는지 궁금할 때, strace가 그 답을 보여 줍니다.
도구를 곁에 두기
이 도구들은 평소에는 쓸 일이 없을지 모릅니다. 하지만 문제가 생겼을 때, 이들의 가치는 무엇과도 바꿀 수 없습니다. 연결이 안 될 때는 lsof로 포트 상태를 보고, 데이터가 이상할 때는 tcpdump나 Wireshark로 패킷을 들여다보고, 프로그램의 행동이 의심스러울 때는 strace로 시스템 콜을 추적합니다. 추측 대신 관찰로 문제를 푸는 것, 이것이 능숙한 소켓 프로그래머의 일하는 방식입니다.
이로써 실전 프로토콜을 다루는 PART를 마칩니다. 우리는 프로토콜을 설계하고, 채팅과 HTTP를 구현하고, 동시성을 결합하고, 통신을 관찰하는 법까지 배웠습니다. 여기까지가 이 책의 본문입니다. 다음 PART부터는 별표가 붙은 심화 선택입니다. 본문이 단단히 손에 익었다면, 1만 명의 동시 접속을 감당하는 고성능의 세계로 함께 들어가 봅시다.