프로토콜을 설계한다는 것
프로토콜이라는 말은 거창하게 들리지만, 본질은 단순합니다. 두 프로그램이 서로를 이해하기 위한 약속입니다. 사람으로 치면 언어와 예절입니다. 무전기로 대화할 때 말을 마치며 오버라고 외치는 것도 작은 프로토콜입니다. 이 장에서는 프로토콜을 설계할 때 반드시 정해야 하는 것들을 살펴봅니다. PART 02에서 길이 접두어를 잠깐 맛봤는데, 이제 그 원리를 제대로 정리합니다.
가장 큰 문제, 메시지의 경계
프로토콜 설계에서 가장 먼저 부딪히는 문제는 PART 02에서 배운 그것입니다. TCP는 스트림이라 메시지 경계가 없습니다. 받는 쪽은 한 메시지가 어디서 끝나는지 스스로 알아낼 수 없습니다. 그래서 프로토콜이 가장 먼저 정해야 할 것이 바로 이 경계를 긋는 방법입니다. 크게 두 가지 길이 있습니다.
첫째는 길이 접두어입니다. 데이터를 보내기 전에 그 길이를 먼저 알려 주는 방식입니다. "이제 65바이트를 보낼게"라고 미리 말하면, 받는 쪽은 정확히 그만큼 모으면 됩니다. PART 02의 파일 전송에서 쓴 방법입니다. 길이를 알아야 하니 미리 데이터 크기를 알 수 있을 때 좋고, 사진이나 파일 같은 바이너리 데이터에 특히 잘 맞습니다.
둘째는 구분자입니다. 메시지 끝에 특별한 표시를 붙이는 방식입니다. 줄바꿈 문자가 가장 흔한 구분자입니다. 받는 쪽은 줄바꿈이 나올 때까지 모으면 한 메시지가 됩니다. 사람이 읽을 수 있는 텍스트 명령을 주고받을 때 간편합니다. 다만 데이터 안에 구분자와 같은 문자가 들어 있으면 곤란해지므로 주의해야 합니다.
어느 쪽이든 핵심은 같습니다. 받는 쪽이 한 메시지의 끝을 분명히 알 수 있게 하는 것입니다. 이 약속이 없으면 통신은 뒤죽박죽이 됩니다.
명령과 데이터를 구분하기, 상태 머신
경계를 그었다면, 다음은 메시지의 의미를 정할 차례입니다. 어떤 메시지는 명령이고 어떤 메시지는 데이터입니다. 채팅이라면 닉네임을 정하는 명령, 방을 나가는 명령, 그리고 평범한 대화 메시지가 섞여 옵니다. 프로토콜은 이것들을 어떻게 구별할지 정해야 합니다.
여기서 자주 등장하는 개념이 상태 머신입니다. 통신이 진행되면서 프로그램이 여러 상태를 오가는 것을 말합니다. 예를 들어 채팅 서버는 클라이언트가 막 접속한 직후에는 닉네임을 기다리는 상태일 수 있습니다. 닉네임을 받으면 대화 상태로 넘어갑니다. 같은 메시지라도 어느 상태에서 받았는지에 따라 다르게 해석하는 것입니다.
복잡한 프로토콜일수록 이 상태 관리가 중요해집니다. 지금 어떤 상태이고, 어떤 메시지를 받으면 어떤 상태로 넘어가는지를 명확히 그려 두면, 얽히고설킨 통신도 차분히 다룰 수 있습니다. 우리가 만들 채팅 프로토콜은 단순해서 상태가 많지 않지만, 이 사고방식을 알아 두면 더 큰 프로토콜을 만날 때 길을 잃지 않습니다.
텍스트냐 바이너리냐
프로토콜의 형식도 정해야 합니다. 크게 텍스트 방식과 바이너리 방식이 있습니다.
텍스트 방식은 사람이 읽을 수 있는 글자로 메시지를 구성합니다. 우리가 만들 채팅 프로토콜의 명령처럼 말입니다. 장점은 분명합니다. 눈으로 읽을 수 있어 디버깅이 쉽고, 만들기도 간단합니다. 실제로 HTTP의 요청과 응답도 기본적으로 텍스트입니다. 단점은 같은 정보를 담는 데 바이트를 더 많이 쓴다는 것입니다. 숫자 1000을 글자로 적으면 네 글자지만, 숫자로 담으면 더 적은 바이트로 충분합니다.
바이너리 방식은 정보를 바이트 단위로 빽빽하게 담습니다. PART 02에서 파일 길이를 2바이트, 4바이트로 포장한 것이 바이너리 방식입니다. 장점은 효율입니다. 작고 빠릅니다. 게임이나 센서처럼 작은 메시지를 자주 주고받는 곳에서 빛납니다. 단점은 사람이 눈으로 읽을 수 없어 디버깅이 까다롭다는 것입니다.
정답은 없습니다. 사람이 읽기 쉬운 것이 중요하면 텍스트, 효율이 중요하면 바이너리를 고릅니다. 둘을 섞어 쓰기도 합니다. 이 PART에서는 두 방식을 모두 경험합니다. 채팅 프로토콜은 텍스트로, 그리고 HTTP 역시 텍스트 기반으로 다룹니다.
약속이 곧 호환이다
프로토콜 설계의 의미를 한 문장으로 정리하면 이렇습니다. 잘 정의된 약속은 서로 다른 프로그램, 다른 언어, 다른 회사가 만든 시스템도 대화하게 만든다는 것입니다. PART 02에서 Python과 C가 같은 프로토콜로 파일을 주고받은 것을 떠올려 보세요. 그것이 가능했던 이유는 둘이 같은 약속을 지켰기 때문입니다.
우리가 매일 쓰는 웹이 그 거대한 증거입니다. 어떤 브라우저든, 어떤 서버든 HTTP라는 약속만 지키면 서로 통합니다. 이제 그 원리로 우리만의 약속을 만들어 볼 차례입니다. 다음 장에서 채팅 프로토콜을 직접 설계하고 구현합니다.