2017. 2. 21. 12:02 외국 블로그 번역
[GAFFER ON GAMES] UDP VS TCP
좀더 정확한 정보를 얻거나 실력을 향상시키실 분들은 해당 블로그에 직접 가셔서 여러번 읽어보시길 바랍니다.
출처 : GAFFER ON GAMES
- http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/
TCP / IP
TCP는 'Transmission Control Protocol'이며 IP는 'Internet Protocol'입니다,
위의 두개는 당신이 온라인에서하는 모든 것, 웹 브라우저에서 email을 사용하기 위한 IRC의 기반이 되며 이 모든 것들은 TCP/IP 위에 지어졌습니다.
만약 당신이 TCP 소켓을 사용한 적이 있다면 당신은 이것이 신뢰할 수 있는 연결 기반의 Protocol 이라는 것을 알수 있다. 이것은 단순히 두 장치 사이에 연결을 만들고 두 컴퓨터 간의 데이터를 전송하는 것이 한쪽에서는 파일을 쓰고 다른 한쪽에서는 파일을 읽는 것과 매우 흡사하다는 것을 의미합니다.
이 접속은 신뢰할수 있고 정렬되어 있습니다.
당신이 보낸 모든 데이터는 다른쪽에 도착할 때 당신이 작성한 순서대로 도착하는 것을 보장할 수 있습니다.
이것은 또한 data의 Stream이며 TCP가 주의해서 당신의 데이터를 패킷으로 분할하고 네트워크를 통해 당신에게 보낼수 있도록 합니다.
다시 말하지만 이것은 파일 입출력과 비슷하다는 것을 잊지마세요. 간단합니다!
IP
단순성은 TCP 밑의 저수준의 IP 프로토콜에서 일어나는 일과는 뚜렷한 차이가 있습니다.
여기에는 연결에 대한 개념은 없습니다, 대신 다음 목적지를 향해 한 컴퓨터를 지나가는 패킷이 있습니다.
이것은 사람이 많은 방에서 쪽지를 다른 한사람에게 전달해주는 것으로 볼 수 있습니다.
이것은 해당 사람에게 전달된다는 것을 보장하지 않습니다.
보낸사람은 그저 그 쪽지가 전달되는것을 희망하는것이 최선입니다.
[보낸사람은 그저 쪽지가 전달되기를 바랄 뿐입니다.]
해당 쪽지를 받았는지 아닌지는 절대 알수 없습니다, 다른사람이 답장을 쓰지 않는한 말이죠
물론 현실에서는 위에서 말한것보단 좀더 복잡하게 이루어집니다.
물론 어떠한 컴퓨터도 컴퓨터들을 지나 패킷들이 목적지까지 가장 빠르게 도달하는 정확한 전송과정을 알고있지 못하기 때문입니다.
때때로 'IP는 여러개의 복사된 패킷들에 따라서, 그 패킷들은 목적지까지 다다르는 여러 경로
를 만들어 냅니다., 그래서 제각각 도착시간이 다를수 있습니다.
이것은 인터넷이 스스로 형성되고 스스로 복구되도록 디자인되었기 때문이며
접속문제가 생겨도 주변을 통해 접근할 수 있도록 하기 위해서입니다.
[위 문장 거의 의역]
당신이 실제로 어떻게 도달해야하는지에 대한 낮은 레벨에 대해서 어떻게 진행되는지 생각해보는것도 확실히 멋진 일이다. 당신은 이 내용을 TCP/IP illustrated 책에서 읽을 수 있다.
UDP
두 컴퓨터 사이의 소통을 마치 파일을 쓰는 것처럼 다루는 대신에,우리가 패킷들을 직접 보내고 받는건 어떨까?
우리는 이것을 UDP를 사용함으로써 할 수 있다.
UDP는 유저 데이터그램 프로토콜에 기반하고 이것은 TCP처럼 IP위에서 구현되는 또다른 프로토콜이다. 그러나 이번에는 복잡성과 여러 특징들을 대신 그저 IP위에 매우 얇은 계층을 더할 뿐입니다.
UDP를 통해서 우리는 패킷을 목표IP주소와 port로 보낼수 있습니다.
그리고 이것은 목적지를 향해서 컴퓨터에서 컴퓨터를 통해 도달하거나 혹은 이 과정중에 유실될 수 있습니다.
수신자 측에서, 우리는 단지 특정 포트를 통해 기다릴수 있으며[listen]
익명의 컴퓨터로부터 패킷이 도착했을 때, 우리는 그제서야 패킷을 보낸측의 주소와 port를 알 수 있다.
[위 내용은 UDP는 실제 컴퓨터간의 연결을 통한 전송이아니라 목적지만 정하고 전달하는 특징 때문]
UDP는 순서를 유지해주지 않는 프로토콜이다.
실제로 대부분의 전송된 패킷은 실제 전송한 것에 비해서 1~5%센트가 유실된다.
그리고 경우에 따라서 모든 패킷을 못받는 시기가 올 수 도 있다.
[당신과 당신이 원하는 목적지 사이에 수많은 컴퓨터들이 있기때문에 잘못 전달될 수 있다는 것을 명심해라]
그리고 UDP는 패킷의 순서를 보장해주지 않는다.
만약 5개의 패킷을 보냈다면 이것들은 3,1,2,4,5 순서로 도착할 수도 있다.
실제로 패킷들은 대부분의 경우에는 순서대로 도착한다.
다만 보장할 수 없다는 것이다.
[왠만하면 순서대로 오지만 결국 확인을 해야된다는 말]
마지막으로, 대부분의 UDP는 IP프로토콜의 위에 많은것을 추가하지 않았지만,
이것은 단 한가지를 당신에게 보장한다.
만약 당신이 패킷을 보냈다면, 이것은 보낸패킷들이 전부다 도착하거나 전부다 도착하지 않는다는 것이다.
따라서 만약 당신이 256바이트의 패킷을 다른 컴퓨터로 보냈다면, 그 컴퓨터는 100바이트만 수신하지 않고 256바이트의 모든 데이터를 받는다.
이것이 UDP가 당신에게 보장하는 단 한가지이다.
TCP와 UDP
우리는 TCP와 UDP 사이에서 어떤 것을 사용할 지 결정을 해야한다.
각각의 특징을 알아보자.
TCP
- 접속기반 프로토콜
- 순서와 신뢰성을 보장한다.
-> 여기서의 신뢰성은 보낸 메세지가 유실되지 않는다는 것.
- 당신을 위해서 패킷에 저장된 data를 끊어준다.
- 이것은 내부연결을 핸들링하여 보내려는 데이터가 너무 빨리 전송되지 않도록 합니다.
- 사용하기에 쉽습니다, 당신은 그저 파일을 읅거나 쓰는것과 같은 작업을 하면 됩니다.
UDP
- 연결[혹은 접속]이라는 개념이 없으며, 당신 스스로 이것에 대한 처리를 코드를 작성합으로써 처리해야 합니다.
- 패킷의 순서 혹은 신뢰성을 보장하지 않습니다. 패킷들은 무작위 순서로 도착하거나, 중복되거나, 혹은 모든 패킷들이 다 도착하지 않을 수 있습니다.
- 당신은 당신의 데이터를 잘라 패킷에 넣고 그것들을 보내야합니다.
- 당신은 데이터가 인터넷연결보다 빠르게 전송되지 않도록 다뤄야 할 필요가 있습니다..
- 만약 패킷이 유실되었다면, 당신은 이것을 알아 채고 필요하다면 데이터를 다시 전송할 방법이 필요합니다.
결정은 꽤 간단해보입니다, UDP는 우리가 모든 코드를 작성해서 고통을 받는 동안 TCP는 우리가 사용하기 쉽습니다.
그렇다면 우리는 바로 TCP를 선택해야 할까요?
틀렸습니다.
TCP를 사용하는 것은 최악의 경우 FPS같은 게임을 개발할 때 실수를 일으킬 수 있습니다.
왜 그런지 생각해봅시다. 당신은 TCP가 실제로 IP위에서 모든것을 간단하게 작업하는지에 대해서 살펴봐야 할 필요가 있습니다.
그렇다면 TCP는 실제 어떻게 작동하는가?
TCP와 UDP는 모두 IP를 기반으로 만들어 졌습니다.
그러나 둘은 근복적으로 차이점이 있습니다. UDP는 밑에있는 IP와 매우 흡사하게 행동합니다.
TCP는 파일 입출력처럼 느끼도록 모든것을 추상화하여 당신에게 패킷의 복잡성과 비신뢰성을 모두 숨김니다.
그렇다면 이것은 어떻게 이루어 지는가?
우선, TCP는 스트림기반의 프로토콜입니다.
따라서 당신은 그저 바이트 스트림을 작성하면 되며, TCP는 해당 스트림이 반대편까지 가로질러 가는것을 보장합니다.
IP는 패킷기반이며, TCP는 이 IP 위세 구축되었고, 그러므로 TCP는 반드시 당신의 데이터스트림을 패킷안에 잘라 넣어야 합니다.
이제 당신이 보내려는 데이터를 TCP는 코드 내부의 대기열에 넣습니다, 그러면 대기열에 데이터가 충분히 모였을 때 TCP는 패킷을 다른 장치에 전송합니다.
이것은 멀티플레이 게임에서 문제를 일으킬 수 있습니다.
만약 당신이 매우 작은 패킷을 보냈다면, TCP는 충분한 양의 데이터가 모이지 않았다고 판단하는 일이 발생할 수 있습니다.
이게 왜 문제냐면, 당신은 클라이언트에게서 입력정보를 가능하면 빨리 얻고 싶을것이기 때문입니다.
만약 TCP가 작을 패킷을 처리하는 것때문에 딜레이되거나 "엉망이 된다면", 클라이언트 유저는 게임이 거지같다고 느낄것입니다.
게임 네트워크는 주기적인 대신 우리가 원하는것처럼 빈번하게 수신되어야 합니다
TCP는 TCP_NODELAY라는 옵션을 지정할 수 있습니다.
이 옵션은 TCP가 충분한 데이터가 모이지 않더라도 당신이 데이터를 작성한 그 즉시,
더 기다리지 않고 전송하도록 합니다.
이것은 경우에 따라서 Nagle 알고리즘을 사용하지 않는 방법으로 제공됩니다.
불행히도, 만약 당신이 이 옵션을 사용한다고 해도, TCP는 멀티플레이어 네트워크 게임에 사용하기에는 매우 중대한 문제점을 지니고 있습니다.
이 모든것은 TCP가 신뢰성과 순차성같은 환상을 당신에게 보여주기 위해서 어떠한 방법으로 손상되거나 순서가 없는 패킷들을 다루는지에서 시작됩니다.
실제로 TCP는 어떻게 구현되어 있을까?
기본적으로 TCP는 패킷안에 데이터를 자르고, 이 패킷을 IP를 통해 신뢰성 없이 전송한다.
그러면 반대편에서 이 패킷을 수신 후 스트림으로 재구성한다.
그렇다면 패킷이 유실되었을때는 어떤일이 일어나는가?
패킷이 순서 없이 도착하거나 망가지면 어떠한 일이 일어나는가??
어떻게 TCP가 작동하는지에 대해 깊게 들어가지 않아도
TCP가 ACK를 수신하지 못해서 패킷이 유실되었다는 것을 알아차릴 때까지의 TCP의 전송방식은 기본적으로 매우 복잡하다.
중복된 패킷은 수신자 측에서 폐기되며 순서가 없는 패킷은 재정렬되기 때문에 모든것이 신뢰할수 있고 정렬된다.
문제는 만약 패킷이 누락될 때마다 우리가 TCP를 통한 동기화를 하려고 할 때,
패킷을 다시 보내기 위해서 동기화를 멈추거나 지연시킨다는 것이다.
그렇다, 심지어 최신 데이터를 받았을 때도 최신 데이터를 큐에 넣고,
그리고 당신은 누락된 패킷이 재전송될때까지 이것에 접근할 수 없다.
패킷을 다시 보내려면 얼마나 걸릴까?
이것은 TCP로 데이터를 다시 보내 해결하기 위해서 최소 왕복하는 대기시간이 필요하다.
그러나 평균적으로 이것은 두배의 왕복시간[RTT (Round Trip Time )],
그리고 발신자가 수신자에게 재전송할 패킷이 도달하는데 걸리는 시간이 필요하다.
따라서 만약 당신이 125ms의 ping을 갖고 있다면, 당신은 최선의 경우에도 패킷을 재전송하기위해서 1/5초를 기다려야 하며, 최악의 경우에는 상황에 따라서 당신은 1/2초 또는 더 오랜 시간을 기다려야 한다.
(재전송하는것이 또 실패할 수 있다는 것을 생각해보아라)
만약 TCP가 네트워크 손실을 나타내는 패킷을 잃어버리고 이것이 작동한다면 무슨일이 벌어질까? 매우 재밌어 질것이다.
왜 당신은 TCP를 네트워크 시간에 민감한데이터에 사용하면 안될까?
실시간 FPS게임에 TCP를 사용하는 문제는 Web브라우저 또는 e메일, 대부분의 App과는 비슷하지 않다는 것이다. 멀티플레이어 게임은 실시간으로 패킷의 전달을 요청한다.
당신의 게임 중 많은 부분, 플레이어 입력과 케릭터의 위치를 예로 들 수 있다.
이것은 실제로 몆초전에 어떤일이 일어났는지 신경쓰지 않으며, 당신은 오직 최신 데이터만 신경쓰면 된다. TCP는 이점을 염두해두고 설계되지 않았다.
멀티플레이어 게임의 매우 단순한 예를 고려해보면, 일종의 '슈터'같은 액션게임이 있다.
당신은 아주 간단한 방법의 네트워크를 원한다.
당신이 매 프레임마다 크라이언트에서 서버로 보낸 입력, 그리고 서버에서 매 프레임마다 처리하는 각각의 플레이어로부터의 입력, 시뮬레이션 처리, 게다가 랜더링을 위해서 클라이언트에게 게임 오브젝트의 현재 위치를 보낸다.
그래서 우리의 단순한 멀티플레이 게임에서는, 패킷을 잃을 때마다,
패킷을 다시 보내는 동안 모두 멈추고 기다려야한다.
클라이언트 게임 오브젝트에서 업데이트 받는것을 멈추면 그것들은 여전히 서있는것처럼 보일 것이다. 그리고 서버에서 클라이언트로부터 얻는 입력이 멈춘다.
그러면 유저는 움직이거나 솔 수 없다.
다시 보낸 패킷이 마침내 도착했을 때, 당신은 낡은것을 받고,
이미 당신이 신경쓰지 않는 지나간 정보를 받는다.
덧붙여서 같은 시간에 도착한 패킷들은 다시 보내는 동안 큐에 저장된 채로 기다리고,
당신은 같은 프레임 내에서 모든 패킷에 대한 처리를 해야 한다.
모두다 엉망이다!
불행히도, 이 것을 고치기 위해서 TCP를 사용해서 당신이 할수 있는 것은 없고, 당신이 원하지 않더라도 이것은 TCP의 기본적인 성질이다.
이것은 그저 신뢰할 수 없는, 패킷 기반의 인터넷을 신뢰성있고 정렬된 스트림으로 보이게 할 뿐입니다.
신뢰성있고 정렬된 스트림은 우리가 원하지 않는 것입니다.
우리는 데이터 손실때문에 재발신을 기다리는 일 없이 클라이언트에서 서버로 가능한 빠르게 받은 데이터를 원합니다.
이것이 우리가 왜 실시간 데이터 네트워킹을 위해서 TCP를 절대 사용하면 안되는지에 대한 이유입니다.
잠깐, TCP와 UDP를 동시에 사용하면 안되는 이유는?
플레이어 입력, 상태와 같은 실시간 게임 데이터를 통해서, 오직 가장 최근의 데이터와 관련되어 있다. 그러나 다른 유형의 데이터는, 하나의 장비에서 다른 장비로 보낸 일련의 명령어라고 말하면, 신뢰성과 순서가 매우 중요할 수 있습니다.
UDP를 플레이어 입력과 상태에, TCP는 신뢰할 수 있고 정렬된 데이터에 사용하는것이 매력적입니다.
만약 당신이 예리하다면 아마도 신뢰할수 있고 정렬된 명령의 "Stream", 아마도 레벨로딩에 대한 것, 그리고 AI에 대한 다른것, 이 여러개가 있다는 점을 스스로 추측할 지도 모릅니다.
"글쎄, 난 난 AI 커맨드가 레벨로딩 커맨드를 보관한 패킷이 손실된다고 해도 사라지지 않기를 원해, 이건 상관없거든"
당신이 맞다, 그러니 커맨드의 흐름을 TCP소켓를 통해 구현하려고 시도할지도 모른다.
표면적으로는, 이것은 매우 좋은 생각같다. 문제는 이것이 TCP와 UDP는 모두 IP의 위에 만들어졌기 때문에, 각각의 프로토콜에 의해 보내진 내부패킷은 서로에게 영향을 줄수 있다는 것이다.
정확히 그것들이 어떻게 서로 영향을 미치는지는 꽤 복잡하고 어떻게 TCP가 신뢰성과 흐름을 제어하는지와 관련되어 있다, 그러나 근본적으로는 당신은 TCP가 UDP패킷들에서 패킷손실을 유발하는 경향이 있다는 것을 기억해야한다.
좀더 자세한정보는 "링크"에 있다.
또한, UDP와 TCP를 섞는것은 꽤 복잡하다.
만약 당신이 UDP와 TCP를 섞는다면 당신은 일정한 양의 제어권을 잃는다
[구현에서 컨트롤할수 있는 부분이 적어진다는 의미인듯.]
아마 당신은 TCP를 사용하는 것보다 더 효과적인 방법을 구현할 수 있을 것이다.
근데 그게 당신이 필요하는것 보다 더 적합한가??
만약 당신이 신뢰성과 정렬된 데이터를 원한다면. 이것은 가능하다,
제공된 데이터가 사용가능한 대역폭에 비해 상대적으로 작으면 TCP를 통해 빠르고 더 안정적으로 보낼 수 있습니다.
거기에, 만약 당신이 집 인터넷으로 다른 누군가에게 말을 하기 위해서 연결을 가능하게 하기 위해서 NAT을 할 필요가 있다면, 이 NAT은 일종의 고통스러운 한번의 UDP 그리고 한번의 TCP(이게 가능할지는 모르겠지만)를 해야만 한다.
결론
내가 추천하는 것은 당신이 UDP만 사용하라는 것도 아니고,
그러나 당신이 오직 UDP를 게임 프로토콜로 사용하라는 것도 아니다.
TCP와 UDP를 섞지 말라는 것이다.
대신 당신이 직접만든 UDP 프로토콜 안에 당신이 사용하길 원하는 TCP의 특별한 조각을 구현하는 방법을 배워라.
[UDP기반으로 신뢰성이 필요하다면 신뢰성 구현하는 걸 배우라는 의미인듯]
물론 이것은 HTTP에서 RESTfull 서비스를 사용해 게임을 하는 동안 다른사람과 말을 하는것은 문제가 안된다.
그것은 내가 말하려했던 것이 아니다.
당신의 게임이 돌아가는 동안의 TCP연결은 모든것을 가져오지는 않는다.
요점은, 당신의 게임 프로토콜을 UDP와 TCP로 구분하지 말라는 것이다.
게임이 돌아가는 동안 UDP를 통해 당신의 게임 프로토콜을 유지한다면 당신은
당신이 보냈고 받은 데이터와 신뢰성, 정렬 및 혼잡함을 방지하는 것을 완벽하게 구현할 수 있습니다.
이 시리즈의 나머지 기사는 당신이 어떻게 이를 구현하고, 가상 연결을 기반으로 UDP위에 프로토콜을 만듬으로부터, 신뢰성을 구축하고, 흐름을 통제와 혼잡성 방지를 보여줍니다.
다음 기사 : 패킷 전송과 수신
'외국 블로그 번역' 카테고리의 다른 글
[Gaffer On Games]Sending and Receiving Packets [작성중] (0) | 2019.11.26 |
---|---|
게임에서의 Hexa Tile에 관하여-좌표체계[작성중] (0) | 2019.10.21 |
게임에서의 Hexa Tile에 관하여-기하학 (0) | 2019.09.29 |
10가지의 일반적인 소프트웨어 구조적인 패턴 (0) | 2019.07.31 |