iBetter Books
수정

TCP를 버리면 무엇이 남는가

TCP는 믿음직한 택배입니다. 물건이 순서대로, 빠짐없이, 망가지지 않고 도착하도록 온갖 장치를 동원합니다. 받는 사람이 서명을 하고, 분실되면 다시 보냅니다. UDP는 다릅니다. UDP는 엽서를 우체통에 넣는 것에 가깝습니다. 주소만 적어 던져 넣으면 끝입니다. 도착했는지, 순서대로 왔는지, 아예 도착하긴 했는지조차 보장하지 않습니다. 이 장에서는 그 가벼움의 정체를 들여다봅니다.

연결이라는 절차가 사라진다

TCP에서 가장 먼저 한 일은 connectaccept로 연결을 맺는 것이었습니다. UDP에는 이 절차가 없습니다. 3-way 핸드셰이크도, listen도, accept도 없습니다. 그저 소켓을 만들고 곧바로 데이터를 던지면 됩니다.

그래서 UDP 소켓에서 쓰는 함수도 다릅니다. TCP에서는 연결된 상대에게 sendrecv로 주고받았지만, UDP에서는 매번 주소를 함께 지정합니다. 보낼 때는 sendto로 데이터와 받는 사람의 주소를 함께 넘기고, 받을 때는 recvfrom으로 데이터와 보낸 사람의 주소를 함께 받습니다. 엽서마다 받는 주소와 보낸 주소를 적는 것과 같습니다.

소켓을 만들 때도 한 글자가 달라집니다. TCP는 SOCK_STREAM이었지만 UDP는 SOCK_DGRAM을 씁니다. 데이터그램, 곧 한 덩어리씩 주고받는 소켓이라는 뜻입니다.

UDP가 보장하지 않는 것들

UDP의 성격을 정확히 알려면, 무엇을 보장하지 않는지를 분명히 해야 합니다. 세 가지입니다.

첫째, 도착을 보장하지 않습니다. 보낸 데이터그램이 네트워크 어딘가에서 사라져도 UDP는 알려 주지 않습니다. 보낸 쪽은 도착했다고 믿지만 받는 쪽은 받지 못했을 수 있습니다.

둘째, 순서를 보장하지 않습니다. 먼저 보낸 데이터그램이 나중에 보낸 것보다 늦게 도착할 수 있습니다. 서로 다른 경로로 흘러갈 수 있기 때문입니다.

셋째, 중복이 없음을 보장하지 않습니다. 같은 데이터그램이 두 번 도착할 수도 있습니다.

대신 한 가지는 지킵니다. 데이터그램이 도착한다면, 그것은 보낸 그대로의 한 덩어리로 도착합니다. TCP처럼 잘게 쪼개져 흘러오는 일은 없습니다. 엽서가 반쪽만 배달되는 일은 없는 것과 같습니다. PART 02에서 우리를 괴롭히던 부분 수신 문제가 UDP에는 없는 셈입니다. 한 번의 recvfrom이 한 개의 데이터그램을 통째로 줍니다.

그런데 왜 UDP를 쓰는가

이렇게 못 미더운 UDP를 도대체 왜 쓸까요. 가볍고 빠르기 때문입니다.

연결을 맺는 왕복이 없으니 곧바로 데이터를 보낼 수 있습니다. 도착을 확인하고 재전송하는 부담이 없으니 지연이 적습니다. 그래서 약간의 손실보다 속도가 중요한 곳에서 빛을 발합니다.

실시간 영상 통화나 게임을 떠올려 보세요. 0.5초 전의 화면 한 장이 늦게라도 꼭 도착하는 것보다, 그 한 장은 버리더라도 지금 이 순간의 화면이 빠르게 오는 편이 낫습니다. 늦게 도착한 과거의 데이터는 쓸모가 없기 때문입니다. 센서가 1초에 수십 번 보내는 측정값도 마찬가지입니다. 한두 개 빠져도 다음 값이 곧 오니 큰 문제가 아닙니다. 이름을 주소로 바꿔 주는 DNS 조회처럼 짧은 질문 하나와 답 하나로 끝나는 통신도, 연결을 맺을 가치가 없으니 UDP가 어울립니다.

TCP와 UDP, 무엇을 고를까

둘 중 무엇을 쓸지는 결국 무엇이 더 중요한가에 달려 있습니다.

데이터가 하나도 빠지면 안 되고 순서가 중요하다면 TCP입니다. 파일 전송, 웹 페이지, 메신저 대화처럼 정확성이 생명인 경우입니다. 반대로 속도와 실시간성이 정확성보다 중요하고 약간의 손실을 견딜 수 있다면 UDP입니다. 실시간 스트리밍, 게임, 센서 데이터가 여기에 속합니다.

한 가지 덧붙이면, UDP의 가벼움은 가지면서도 신뢰성이 일부 필요할 때는 신뢰성을 직접 더하는 길도 있습니다. 실제로 요즘 웹을 빠르게 만드는 최신 프로토콜들이 바로 이 방식을 택합니다. 그 이야기는 잠시 뒤 신뢰성을 직접 더해 보는 장에서 맛보게 됩니다.

성격을 파악했으니, 이제 실제로 UDP 서버와 클라이언트를 만들어 볼 차례입니다.