【实战】Unity3d实战之Unity3d网络游戏实战篇(3):网络基础之TCP协议

Unity3d实战之Unity3d网络游戏实战篇(3):网络基础之TCP协议

学习书籍《Unity3d网络游戏实战》 罗培羽著 机械工业出版社
本文是作者在学习过程中遇到的认为值得记录的点,因此引用的代码等资源基本出资罗培羽老师的书籍
以下为个人的学习简记,与诸君共论 由于U3D的官方案例Tank Tutorial中对坦克的基本操作已经有了详尽的描述,因此本文着重于面板系统、服务端基本网络框架和客户端基本网络框架的搭建
如有疑问或者描述错误的地方,欢迎各位提出或修正,讨论交流是获取和巩固知识的重要途径之一!

网络基础
 制作一款网络游戏必不可少的就是网络基础知识了,网络上有很多关于网络七层模型、IP与端口的说明文章,这里就不意义赘述了。主要说一下TCP。
 TCP是Transmission Control Protocol(即传输控制协议),它是面向连接的、可靠地数据传输服务(另外一种是UDP(User Datagram Protocol用户数据报协议,提供无连接的不可靠的数据传输服务))。
 TCP连接的建立和终止一直被戏称为三次握手四次挥手,因为在这两个阶段中,客户端和服务端之间通信就像是握了三次手,挥了四次手…
 说TCP连接的建立之前先说明几个术语以及规则:
 SYN:同步位    seq:序号
 ACK:确认位    ack:确认号
 FIN:终止控制位 
 
 SYN报文段(即SYN=1的报文段)不能携带数据,但要消耗掉一个序号,即seq要加1;
 ACK报文段可以携带数据,但如果不携带数据则不消耗序号;
 FIN报文段可以携带数据,但如果不携带数据也要消耗一个序号;
 第二次握手的报文段也不能携带数据,但同样要消耗掉一个序号,即seq要加1;
 
  【实战】Unity3d实战之Unity3d网络游戏实战篇(3):网络基础之TCP协议_第1张图片
 三次握手过程:
  第一次握手:Client向Server发出连接请求报文,该报文首部的SYN设为1。同时Client为自己选择一个初始序号seq = x,Client进入SYN-SENT状态。由于SYN报文消耗一个序号,因此Server收到的序号为x+1;
  第二次握手:Server收到连接请求报文后,如同意连接,则向Client发送确认报文,确认报文首部SYN和ACK都置为1,ack = x+1,同时Server为自己选择一个初始序号seq = y,Server进入SYN-RCVD状态;
  第三次握手:Client收到Server的确认报文后,还要给Server发送确认报文进行确认,确认报文首部ACK置为1,ack = y+1,seq = x+1,Client进入ESTABLISHED状态。由于ACK报文段如果不携带数据则不消耗序号,故下一次Server接收到的序号仍为x+1。
  Server收到Client的确认报文后,Server也进入ESTABLISHED状态。至此完成三次握手。
  疑问:
   为什么Client最后还要发送一次确认?
    首先定义“已失效的连接请求报文段”:Client发出第一个连接请求报文段,但由于网络滞留,导致在第二个连接请求报文段被Server接收后才到达Server,第一个连接请求报文段即为“已失效的连接请求报文段”。
    Server接收到“已失效的连接请求报文段”,会误认为Client又发出一次新的连接请求,并向Client发送ACK报文。由于Client并没有发出第三次的连接请求报文,因此不会作出回应,Server却以为新连接已经建立并一直等待Client发送数据,Server的资源就这样被白白浪费了。

【实战】Unity3d实战之Unity3d网络游戏实战篇(3):网络基础之TCP协议_第2张图片
 四次挥手过程:
  第一次挥手:假设Client先发出连接释放报文并停止再发送数据,报文首部FIN置为1,序号seq = u(u等于前面已传送过的数据的最后一个字节的序号+1),Client进入FIN-WAIT-1状态,等待Server确认。由于FIN报文消耗一个序号,因此Server收到的序号为u+1;
  第二次挥手:Server收到连接释放报文后即向Client发送确认报文,报文首部ACK置为1,ack = u+1, seq = v(等于前面已传送过的数据的最后一个字节的序号+1)。Server进入CLOSE-WAIT状态。
  注意:此时TCP连接处于半关闭状态,即Client不再发送数据,但Server若发送数据,Client仍要接收。Client在接收到Server的确认报文后进入FIN-WAIT-2状态,等待Server的下一次挥手。
  第三次挥手:若Server已经没有要向Client发送的数据,则向Client发送连接释放报文,报文首部FIN置为1,ack = u+1,假定Server的seq = w(由于TCP在半关闭状态下Server可能又发送了数据)。Server进入LAST-ACK状态。由于FIN报文消耗一个序号,因此Client收到的序号为w+1;
  第四次挥手:Client收到Server的连接释放报文后,向Server发送确认报文,报文首部ACK置为1,ack = w+1,seq = u+1。Client进入TIME-WAIT状态。
  注意:此时TCP连接还未释放,必须经过时间等待计时器(TIME-WAIT timer)设置的MSL时间后,Client才进入到CLOSED状态、MSL(Maximum Segment Lifetime),才能开始建立下一个新的连接。

 疑问:
  为什么Client在TIME-WAIT状态必须等待MSL时间?
  1. 为了保证Client发送的最后一个确认报文能够到达Server。
   在Client发送ACK报文后,该报文可能会丢失,Server收不到确认就会重传一次FIN+ACK报文,而Client就能在MSL时间内接收到这个FIN+ACK报文,重新启动计时器,直到Client和Server都进入CLOSED状态;
   若Client不等待MSL时间,直接释放连接就接收不到Server的重传FIN+ACK报文,Server就无法正常进入CLOSED状态。
  2. 防止“已失效的连接求情报文段”出现在本次连接中。经过MSL时间后,本TCP连接持续时间内产生的所有报文段都将从网络中消失,这样能保证下一个新连接中不会出现这类旧报文。注意,Server结束TCP连接的时间要比Client早一点。

附上一张示例图:
【实战】Unity3d实战之Unity3d网络游戏实战篇(3):网络基础之TCP协议_第3张图片

你可能感兴趣的:(实战集,Unity3d)