网络游戏如何使用UDP提供可靠传输

  UDP本身不提供可靠传输,但是传输效率比TCP高。能提供可靠传输的UDP应该是UDP和TCP的某种折衷,这样它才能提供可靠的,有效率的传输。
  所以我们得先了解TCP使如何提供可靠传输的,再看看TCP效率不高的原因是什么,最后提出一种可靠的UDP传输方案。

TCP是如何提供可靠传输
  • 建立连接(标志位):通信前确认通信实体存在。
  • 序号机制(序号、确认号):确保了数据是按序、完整到达。
  • 数据校验(校验和):CRC校验全部数据。
  • 超时重传(定时器):保证因链路故障未能到达数据能够被多次重发。
  • 窗口机制(窗口):提供流量控制,避免过量发送。
  • 拥塞控制:同上。
TCP不用于网络游戏的原因
  • 首先,TCP是一个流式协议,所以你只需写数据到一个流,TCP会确保它们到达另一方。因为IP协议是建立在数据包上的,而TCP协议又是建立在IP协议上的,因此TCP必需将你的流式数据拆分成数据包。所以,一些内部的TCP代码将你发送的数据放入消息队列,当队列中有足够的数据,它才会发包给另一个机器。这就会有一个问题,如果你发送一个很小的数据包。TCP可能会决定它不会立即发送数据,直到缓冲区有足够的数据组成一个合理大小的包。这样客户端的体验就会很差。
      TCP有个选项,你可以用来修复它的这种行为,叫作“TCP_NODELAY”。这个选项通知TCP不用等到队列中有足够的数据,立即发送你写入的任何数据。

  • 更关键的是TCP可靠性在于重发和重组。当一个数据包丢失后,就不得不停下来,等待这个数据包重传。即使最近的数据达了,新的数据已经到达队列了,你还是不能读取它,直到你收到了丢掉的数据包。

如何用UDP实现可靠传输

  UDP的可靠传输实现分为两部分“可靠性”和“避免拥堵”。

  • 可靠性:采用重发机制。

    • 类似TCP的ack机制。关于丢包检查,可以采用一个近似TCP的ack机制,可以给每个数据包都添加一个sequence ID,然后发送端就依次发送数据包,接收端收到数据包后就可以根据sequence ID来判断是否有丢包了。接收端需要发该sequenceID的ack给发送端,发送端才会知道这个包是否已经送达。与TCP不同的是如果数据包n丢失了我们也从不暂停重新发送它,而是把它留给应用程序来编写一个包含丢失数据的新的数据包,必要的话,这个包还会用一个新的序列号发送。ack本身也有可能丢包。
    • 可以这样,发送一个sequence ID的ack时,附加一个32bit的位序列,表示当前sequence ID之前的32个连续顺位的数据包是否已经送达。其实就是冗余的发送连续32个包的送达状态,如果bit为0说明这个包还没到,如果为1,说明已经收到了。这样一来,除非连续丢包30多次,ack是一定会送到的,这种几率已经非常小了。
    • 相应的,在发送端设置一个超时机制,这个时间差不多比连续发30个ack的时间长一点,如果发送一个包后开始计时,达到超时还没有收到ack,这个包就丢失了。
    • 最后发现了丢包也不一定需要重发。是否重发可以和游戏逻辑结合起来。因为游戏战斗的同步速率很高,丢一个没有很大影响。
  • 避免拥堵

    • 衡量往返时间(RTT):对我们发送的每个数据包,我们对数据包队列中包含的序列号和他们发送的时间添加一个登记。
      当我们收到一个应答时,我们找到这个登记并记录本地时间和我们收到这个应答的时间以及我们发送数据包的时间的不同之处。这是这个数据包的RTT时间。
    • 通过往返时间来调整数据包的个数。当网络条件好的时候我们每秒发送30个数据包,当网络条件差的时候我们降至每秒10个数据包。

参考

猜你喜欢

转载自blog.csdn.net/nikoong/article/details/79711216
今日推荐