UDP와 TCP 프로토콜은 여러가지 차이점이 있지만 프로그래밍을 할 때 필수적으로 이해해야 할 숨겨진 개념이 있습니다. 그것은 UDP는 메시지를 기반(Message-oriented)한 프로토콜이고 TCP는 스트림을 기반(Stream-oriented)한 프로토콜이란 점입니다. 이로 인해 구현 코드에도 중요한 차이가 발생하니 유의해야 합니다.
UDP는 Message-oriented 프로토콜입니다.
UDP는 Sender가 100바이트를 전송하면, 100바이트를 하나의 메시지로 인식하고 Receiver가 한 번의 읽기 동작으로 100바이트를 수신할 수 있도록 해줍니다. Sender가 100바이트, 200바이트, 300바이트 가변적으로 보내도 마찬가지죠.
이를 위해 UDP 헤더에는 메시지 길이 필드(사용자가 전송 요청한 메시지 길이) 2바이트가 있습니다. 이로 인해 한 번에 전송할 수 있는 메시지 크기가 2바이트로 표현할 수 있는 크기로 제한이 생깁니다.
물론 UDP는 TCP처럼 신뢰성있는 채널이 아니라 손실되거나 변형될 가능성은 있습니다. 그래서 실무에서는 응용계층에서 메시지 유효성 검사를 수행하거나(CRC, CheckSum 등) 메시지 순서 번호를 직접 메겨서 순서를 확인하는 경우가 있습니다.
TCP 는 Stream-oriented 프로토콜입니다.
이말은 곧 원격지에서 "ABC" 메시지와 "DEF" 메시를 전송하면 TCP는 이를 두개의 독립된 메시지 ("ABC", "DEF")로 인식하지 않고, "ABCDEF" 라는 하나의 스트림으로 인식한다는 겁니다. 그래서 TCP는 대부분 "ABC", "DEF"를 나누어 보내주지만 상황에 따라 한번에 "ABCDEF"를 보낼 수도 있고, 때로는 "ABCDE", "F"를 보낼 수도 있다는 뜻입니다. 이건 버그가 아니고, TCP의 특성입니다.
우리는 TCP 특성에 맞게 메시지 바운더리를 구분해 주는 로직을 사용자 코드에 항상 추가해 주어야 합니다. 메시지 바운더리를 구분해주는 응용계층의 메커니즘은 크게 아래 정도로 구분할 수 있습니다. 각 응용계층 프로토콜에 맞게 반드시 메시지 바운더리 구분로직을 추가해야 안정적인 네트워크 프로그램 작성이 가능합니다.
TCP는 UDP와 달리 헤더에 메시지에 대한 길이(사용자가 전송 요청한 메시지 길이) 필드가 없고 Sequence Number라는 필드가 있어 Stream의 몇 번째 바이트부터 전송되고 있는지 표현해 줍니다.
그러나 TCP는 손실되거나 변형되지 않는 신뢰성있는 채널을 제공합니다.