RUDP之一 —— UDP VS TCP
原文:http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/
介绍
大家好,我是Glenn Fiedler,欢迎阅读我的网上电子书《游戏程序的网络设计》第一章。
在这一章中,我们将从网络编程的最基本方面开始,通过网络收发数据。这是一切的开始—网络程序员工作中最简单和最基本的操作,但最佳的网络通讯策略还是很复杂并且不明显。小心一点,因为如果你在这一步出错了,会对你的多人游戏中造成很可怕的影响。
你或许很可能听过套接字,并且可能意识到这里有两种主要的方法:TCP和UDP。当编写一个网络游戏时,我们首先需要选择使用哪种类型的套接字。我们是使用TCP,UDP,还是同时混合使用。
你所做的决定完全取决于你编写的网络游戏是哪种类型。基于这点考虑和这系列剩余的文章,我假定你是编写一个动作游戏,诸如此类:Halo, Battlefield 1942, Quake, Unreal, CounterStrke, Team Fortress。
在我们打算编写动作游戏的情况下,我们需要进一步观察各种类型套接字的性能,更深入了解互联网的实际工作情况。一旦我们了解清楚了所有的这些信息,我们会很容易做出正确的选择。
TCP/IP
TCP表示“传输控制协议”,IP 表示 “互联网协议”。它们几乎是你网上所做一切操作的基础,从网页浏览器到IRC到电子邮件,所有的一切都是在TCP/IP的基础上建立起来的。
如果你曾经使用过TCP套接字,你就会知道它是基于可靠的连接协议。简而言之,你在两台机器之间建立起连接,然后你在两个计算机传输数据就像是在一台上写文件,然后在另一台上读文件。
这个连接是可靠而且有序的,意味着你所有传输的数据到达另一台计算机时,数据的顺序和你写入的顺序是一样的。它也是流式数据,意味着TCP将你的数据分拆成数据包并且通过网络传输这些数据。
再次,请记住这就像是写一个文件。很简单!
IP
TCP的简单与实际运行的下层IP协议形成鲜明的对比。
这里没有连接的观念代替包从一个计算机到另一个计算机。你可以相像这个过程就像是在一个拥挤的房间,从一个人手里传到另一个手里一张纸条,在经过多个人手传递后才到达最终目的地。
并不能保证这张纸条一定会送到目的人手中。传递者一直传递纸条并做最好的打算,从不知道这个纸条是否会被下个人收到,除非下个人有回执过来。
当然,实际情况更加复杂,因为没有一台计算机知道确切的序列号这个包经过哪些计算机,以便更快地达到目的地。有时IP传递同一个包的多个副本,这些包通过不同的路径达到目的地,所以它们很可能在不同的时间达到。
这是因为互联网被设计为自己组织和自己重复,以绕过连接问题。在低级上的实际工作普遍放实际更酷,你可以阅读一些经典的关于TCP/IP的插图书。
UDP
如果不像写文件一样在电脑间进行通讯,我们该如何直接的发送和接收数据包呢?
我们还能使用UDP来操作。UDP表示“用户数据包协议”,它是基于IP的另一个协议,和TCP类似,但这次并没有添加大量的功能和复杂性,只是做了很简单的一层封装。
通过UDP我们可以直接向目的IP(比如:112.140.20.10)和端口(比如:52423)发送数据包。这个数据包会在一个个电脑间传递,直到达到目的地,或者在传递途中被丢掉。
作为接收者,我们只是在这里监听指定的端口(比如:52423),当从其它电脑传递过来一个数据包(记住这里没有连接了!)我们会注意到发送这个数据包的电脑的端口和IP地址,这个包的大小,并且可以读这个包的数据。
UDP是不可靠传输协议。事实上,大多数的数据包都能正常到达,但通常有1%--5%的丢包率,并且偶尔可能一个包也收不到(记住在你和目的计算机之间存在大量的计算机,它们可能会出错…)
包的顺序通常也没保证。可能你发送五个包以1,2,3,4,5的顺序,但这些数据包完整达到目的地时,顺序可能变成3,1,2,5,4。事实上,它们在所有的时间上都是按顺序达到,但这是不能保证的。
尽管UDP并没有在IP协议上层做过多的操作,但它能够保证一点。如果你发了一个包,它要么会全部达到目的地,要么就全部丢失。所以如果你发送256byte的一个包到另一个计算机,那么那台计算机不可能只收到这个包的初始100bytes数据,它肯定能得到全部的256bytes的数据。这是你使用UDP得到的唯一保证,而其它的一切都是由你决定的。
TCP vs.UDP
现在我们要做出决定,我们是使用TCP套接字还是使用UDP套接字。
我们来看下各自的特点:
TCP:
基于连接的
可靠性和顺序保证
自动将你的发送数据打包
在互联网连接中确保数据不会发送的过快(流控制)
方便使用,你读和写数据,就和操作文件一样
UDP:
没有连接的概念,你不得不自己写代码
不能保证数据包传输的可靠性和顺序性,它们可能顺序达到,也可能出现重复包,甚至一个也不达到
你必须自己将发送数据打包然后进行发送
你必须自己确保网络连接在掌控中,发送数据不能过快
如果一个包丢掉了,你需要设计出几中方法来发现,如果必要的话,要设法重传
这个决定似乎很明确了,TCP做了我们想做的所有事,并且超级简单,而UDP则十分不便,我们不得不自己从头编写所有的代码。所以很明显,我们应该使用TCP对吧?
错了。
当你设计一个网络游戏时,使用TCP可能是你做得最差的选择。为了理解为什么,你需要去观察下基于IP协议的TCP让一切变得如此简单的实际工作方式。
TCP的实际工作方式
TCP和UDP都是基于IP协议的,但它们根本不同。UDP的表现很明显工作在IP协议之上,但TCP抽象了一切操作,使用它就像是读写一个文件,对你隐藏了传送数据包的复杂和不可靠。
但它究竟是如何做到这点呢?
首先,TCP是一个流式协议,所以你只需写数据到一个流,TCP会确保它们到达另一方。因为IP协议是建立在数据包上的,而TCP协议又是建立在IP协议上的,因此TCP必需将你的流式数据拆分成数据包。所以,一些内部的TCP代码将你发送的数据放入消息队列,当队列中有足够的数据,它会发包给另一个机器。
在多人游戏中,这就会有一个问题,如果你发送一个很小的数据包。这里会发生什么呢?TCP可能会决定它不会立即发送数据,直到缓冲区有足够的数据组成一个合理大小的包(通常大约是超过100 bytes)。这就有一个问题,因为你希望你的客户端的操作尽可能快地达到服务器,如果它有延迟或者像TCP那样被当作小的数据包“收集”起来,那么客户端的用户体验就会很差。网络游戏的更新就会迟到和少见,而不是像我们想像中的那样准时和频繁。
TCP有个选项,你可以用来修复它的这种行为,叫作“TCP_NODELAY”。这个选项通知TCP不用等到队列中有足够的数据,立即发送你写入的任何数据。
不幸的是,即使这样,对于多人游戏TCP还是有一些很严重的问题。
这一切都源于TCP处理数据包丢失和次序方式,给你一种错觉,可靠、有序的数据流。
TCP如何实现可靠性
从根本上讲,TCP将数据流拆成包,通过不可靠的IP协议发送数据包,然后在另一端接收这些数据包,并还原成数据流。
但如果一个数据包丢失会发生什么呢?如果一个数据包达到的顺序出错或者重复出现时,又会发生什么呢?
不用去知道TCP工作的过多细节,因为那实在是太难懂了(请参考TCP/IP插图)。本质上TCP发送一个数据包,发现数据包丢失后,就会重传这个数据包到另一台机器。重复的数据包在接收方被丢掉,次序出错的数据包会重组,所以一切都变得可靠和有序。
问题是我们如果使用TCP来进行同步,当一个数据包丢失后,就不得不停下来,等待这个数据包重传。是的,即使最近的数据达了,新的数据已经到达队列了,你还是不能读取它,直到你收到了丢掉的数据包。需要多长时间,它才会重新发包呢?这将花费TCP计算出哪些数据需要重发至少往返延迟,并且另一个单程发送者重发数据包给接收者。所以如果ping 125ms,最佳情况下你将大概等待 1/5th 秒来完成数据包的重发,在最坏的情况下你甚至要等上一分钟或更长(考虑到重发数据失败?)
为什么你不应该使用TCP来设计一个多人游戏的网络
在游戏中使用TCP的问题和浏览器,电子邮件或者大多数程序都不一样,多人游戏在数据包的传输上有一个实时性要求。在你的游戏的很多部分,比如说玩家输入和字符位置,它并不关心一秒前发生了什么,它只是在意最近的数据。
考虑一个多人游戏的非常简单的例子,一些类型的动作游戏比如射击。你希望你的网络很简单。在每一帧你从客户端发送操作数据到服务端(比如按键,鼠标输入,控制输入),并且每一帧服务器处理来自每一位玩家的输入,更新模拟结果,然后把当前的位置返回给客户端进行呈现。
所以在你的简单多人游戏中,当一个数据丢失后,一切都将停止下来等待另一个数据包重发。在客户端游戏角色停止接收更新,所以他们似乎保持静止,在服务端也停止接收客户端的输入信息,所以玩家无法移动或射击。当重发的数据包终于到达,你接收到这个你已经不再关心的旧的数据,过时的信息。另外这里有很多数据包在队列中等待这个重发的数据包,它们将在同时到达,所以你不得不在一帧中同时处理这些数据包。所有的事情都堵在一起。
不幸地是,这里你没法做任何事来改正TCP的这种行为。不管你是否愿意,这都只是它的本质。这也是它所做的使一个不可靠,基于包的网络成为一个可靠的,有序的网络。
我们不需要一个可靠的,有序的命令流。
我们希望自己的数据尽可能快的从客户端到达服务端而不必等待丢失的数据重发。、
这就是为什么多人游戏从不采用TCP来设计网络。
等等?为什么我们不能同时使用UDP和TCP
对于实时游戏数据像玩家的输入和状态,只有最近的数据是有关的,但其它类型的数据,比如从一台机器到另一台机器发送的一系列指令,可靠性和次序性很重要。
所以最佳选择似乎是用UDP处理玩家的输入和状态,TCP处理可靠命令数据。甚至你已经在计算你需要多少个流处理可靠的,次序的命令,似乎一个是关卡载入,一个是AI。或许你自认为,“如果数据包丢失将导致加载一个命令,这是我不想AI命令导致的。它们真没关系。”你是对的,所以你试图为每一个命令流创建TCP套接字。
表面看来,这似乎是个好主意。但问题是TCP和UDP都是基于IP协议的,每个协议潜在的数据包会影响到彼此。他们究竟是如何相互影响是相当复杂的,涉及TCP如何执行可靠性和流控制,但从根本上讲,你要记住易于引起UDP的包丢失。更多信息,请阅读这个章节。
结论
我的建议是你不仅能用UDP,也只能使用UDP。不要混用TCP和UDP,相反了解基于UDP协议如何实现的TCP特定部分。
其余的这个系列文章向您展示如何做到这一点,从创建自己的虚拟连接基于协议在UDP上的,以创建您自己的可靠性和流控制。
接下来,一些更具体的:怎样发送和接收使用UDP数据包
RUDP之一 —— UDP VS TCP的更多相关文章
- 移动端IM系统的协议选型:UDP还是TCP?
1.前言 对于有过网络编程经验的开发者来说,使用何种数据传输层协议来实现数据的通信,是个非常基础的问题,它涉及到你的第一行代码该如何编写. 从PC时代的IM开始,IM开发者就在为数据传输协议的选型争论 ...
- 第五章 运输层(UDP和TCP三次握手,四次挥手分析)
序言 通过这章,可以知道其实三次握手和四次挥手其实真的好简单,通过这章的学习,我相信你也会同样的认为,以后在也不需要听到别人问三次握手的过程而自己一脸懵逼了,觉得人家好屌,其实也就是他懂你不懂,仅 ...
- 网游中的网络编程系列1:UDP vs. TCP
原文:UDP vs. TCP,作者是Glenn Fiedler,专注于游戏网络编程相关工作多年. 目录 网游中的网络编程系列1:UDP vs. TCP 网游中的网络编程2:发送和接收数据包 网游中的网 ...
- DNS分别在什么情况下使用UDP和TCP
DNS同时占用UDP和TCP端口53是公认的,这种单个应用协议同时使用两种传输协议的情况在TCP/IP栈也算是个另类.但很少有人知道DNS分别在什么情况下使用这两种协议. 如果用wiresha ...
- JAVA基础学习day24--Socket基础一UDP与TCP的基本使用
一.网络模型 1.1.OIS参考模型 1.2.TCP/IP参考模型 1.3.网络通讯要素 IP地址:IPV4/IPV6 端口号:0-65535,一般0-1024,都被系统占用,mysql:3306,o ...
- 初识-----基于Socket的UDP和TCP编程及测试代码
一.概述 TCP(传输控制协议)和UDP(用户数据报协议是网络体系结构TCP/IP模型中传输层一层中的两个不同的通信协议. TCP:传输控制协议,一种面向连接的协议,给用户进程提供可靠的全双工的字节流 ...
- 通信协议之HTTP,UDP,TCP协议
1.UDP,TCP,HTTP之间的关系 tcp/ip是个协议组,它可以分为4个层次,即网路接口层,网络层,传输层,以及应用层, 在网络层有IP协议.ICMP协议.ARP协议.RARP协议和BOOTP协 ...
- Http UDP还是TCP
http://1024monkeys.wordpress.com/2014/04/01/game-servers-udp-vs-tcp/ 在编写网络游戏的时候,到底使用UDP还是TCP的问题迟早都要面 ...
- 游戏服务器:到底使用UDP还是TCP
http://blog.jobbole.com/64638/ 在编写网络游戏的时候,到底使用UDP还是TCP的问题迟早都要面对. 一般来说你会听到人们这样说:“除非你正在写一个动作类游戏,否则你就用T ...
随机推荐
- Maven+Spring MVC Spring Mybatis配置
环境: Eclipse Neon JDK1.8.0 Tomcat8.0 先决条件: Eclipse先用maven向导创建web工程.参见本站之前随笔. 本机安装完成mysql5:新建用户xuxy03设 ...
- e-chart 本地加载中国地图
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...
- C#使用 DirectX SDK 9做视频播放器 并在视频画线添加文字 VMR9
视频图像处理系列 索引 VS2013下测试通过. 在百度中搜索关键字“DirectX SDk”,或者进入微软官网https://www.microsoft.com/en-us/download/det ...
- android 性能优化-电量篇
消耗电量的几个主要原因.功能:1.大数据量的网络传输(网络)2.不停的网络切换(网络)3.解析大量的数据(CPU) 关于网络方面的优化: .网络请求之前,检查网络连接.没有网络连接不进行请求 .判断网 ...
- 深入理解javascript原型和闭包(5)——instanceof
又介绍一个老朋友——instanceof. 对于值类型,你可以通过typeof判断,string/number/boolean都很清楚,但是typeof在判断到引用类型的时候,返回值只有object/ ...
- [Head First设计模式]山西面馆中的设计模式——装饰者模式
引言 在山西面馆吃鸡蛋面的时候突然想起装饰者这个模式,觉得面馆这个场景跟书中的星巴兹咖啡的场景很像,边吃边思考装饰者模式.这里也就依葫芦画瓢,换汤不换药的用装饰者模式来模拟一碗鸡蛋面是怎么出来的吧.吃 ...
- SameSite Cookie,防止 CSRF 攻击
因为 HTTP 协议是无状态的,所以很久以前的网站是没有登录这个概念的,直到网景发明 cookie 以后,网站才开始利用 cookie 记录用户的登录状态.cookie 是个好东西,但它很不安全,其中 ...
- Bash 中的环境变量
在 Bash 里,可以通过 export 命令查看当前 Shell 进程的环境变量,这些环境变量一些是 Bash 自己创建的,还有一些是 Bash 从父进程继承来的,然而需要注意的是,父进程传给 Ba ...
- CSS3 之 flexbox 响应式的未来
CSS3 之 flexbox 响应式的未来 flexbox 伸缩盒模型 . flex: CSS3中一个重要的而且非常有用的属性,用来制作弹性布局是非常的方便而又强大. . flex布局:旨在提供一个更 ...
- vue 列表渲染
在Vue官网中写道,vue无法直接用索引设置元素, 如 vm.items[0] = {}: 提出的解决方法是用 : example1.items.$set(0, { childMsg: 'Change ...