tcp为我们做了什么事情?
总得来说,tcp做了这几件事:
udp为我们做了什么事情?
首先应该清楚的是,一个udp数据包仅仅是在IP数据包之上加了一个udp协议头。这个协议头十分精简,仅有的四个字段是:目的端口号、源端口号、数据包长度、校验和。通过sendto这个syscall发送一个udp数据包时,实际上就是包装成一个IP数据包然后直接发送出去。这里并不会像tcp那样在本地缓存数据,直到达到一个长度限制后再发送出去。另外由于有检验和,所以我们不需要在udp之上再做校验的事情了。
一个可靠的udp协议
在清楚tcp做了什么事后,我们就有了实现一个可靠udp的思路了。首先需要说明的是,在udp之上实现一个tcp是没有意义的。实现一个可靠的udp协议往往是,根据业务需要,牺牲掉一部分的tcp的功能,来换取更高的性能。但是,在动手造轮子之前,我们应该分清的是,哪些功能是tcp已经为我们实现了的,而哪些功能是要通过自己定制一个可靠udp来实现的。比如说,上述的第3条,这个特性有时候会造成tcp的延迟性,但是通常可以通过设置TCP_NODELAY来解决。
实现一个最基础的可靠udp通讯协议,我们只需要提供一个重传机制即可。在这我实现了一个简单的可靠udp协议,这个协议为每一个发送出去的udp数据包分配一个包id,每次接收方收到一个数据包时,都要回应发送方一个ack对应这个包id。协议通过这种确认机制来保证接收方能收到发送方发出的udp数据包,在发出的时候,发送方应该设置一个计时器,超时的话会重传数据包。
这个协议做的就是这么多,它仅能确保接收方能收到发送方的udp包,并没有做其它的事情。
具体来说它没做这些事情:
这个协议这么简陋,那要它何用?
首先,对于互相独立的数据包,没有必要保证包的有序性。以游戏开发为例子,玩家在客户端发起一个开宝箱请求的同时,又迅速的切换界面,打开了角色面板又发起一个查看角色数据的请求。保证这两个请求的先后顺序真的有意义吗?
其次,对于大部分的小数据包,没有必要考虑IP分片。玩家发起一个开宝箱的请求,可能整个数据包的内容就是一个请求id和一个宝箱id。假设这两个id都是64位,也就是16字节,整个IP包的大小并不足以让IP层进行分片处理。如果你的系统绝大部分都是这种小包,或许你能不考虑IP分片。
再来谈谈tcp的字节流服务。正如大家所知道的,tcp是提供可靠的字节流服务的。但是,一般情况下我们真的需要传输层提供这种服务吗?以游戏服务器为例子,在用tcp与客户端进行网络通讯上,我们现在的做法是在字节流上对请求、响应进行封包解包,也就是在字节流之上,模拟一个数据包的传输。并且我相信很多其它游戏也是这么做的。数据在IP层上本来就是通过包的形式进行传输,tcp对此做了抽象实现了字节流,应用层又在字节流之上模拟出数据包。是否可以用udp去减少这些不必要的抽象呢?或许我们仅需要的是一个有序可靠的数据包服务,又或许我们连有序性都不需要。。。
总结
最后,我想说的是并没有一套解决方案能适用与所有情况。tcp作为传输层给出的是一套通用性的解决方案,并致力于满足大多数的需求,但是总会有其不适合的地方。这个时候我们就可以使用udp来自己定制一套时候自己业务的协议。这套协议不一定是很复杂,其实实现一个可靠的udp也并不是很复杂,关键要看你需要协议提供什么功能!
参考资料
原文:http://www.cnblogs.com/adinosaur/p/5983233.html