目录
[1. 开发中常见的数据组织格式](#1. 开发中常见的数据组织格式)
[1.1 XML](#1.1 XML)
[1.2 JSON](#1.2 JSON)
[1.3 Protobuf](#1.3 Protobuf)
[2. 端口号](#2. 端口号)
[3. UDP协议](#3. UDP协议)
[4. TCP协议](#4. TCP协议)
[4.1 特点](#4.1 特点)
[4.2 TCP报文格式](#4.2 TCP报文格式)
[4.3 TCP可靠性机制](#4.3 TCP可靠性机制)
[4.3.1 确认应答机制](#4.3.1 确认应答机制)
[4.3.2 超时重传机制](#4.3.2 超时重传机制)
[4.3.2.1 丢包的两种情况](#4.3.2.1 丢包的两种情况)
[4.3.2.2 重传时间](#4.3.2.2 重传时间)
[4.3.3 连接管理机制](#4.3.3 连接管理机制)
[4.3.3.1 三次握手建立连接](#4.3.3.1 三次握手建立连接)
[4.3.3.2 四次挥手释放连接](#4.3.3.2 四次挥手释放连接)
[4.3.3.3 建立连接与释放连接的总过程](#4.3.3.3 建立连接与释放连接的总过程)
[4.4 TCP效率提高机制](#4.4 TCP效率提高机制)
[4.4.1 滑动窗口协议](#4.4.1 滑动窗口协议)
[4.4.1.1 数据传输示意图](#4.4.1.1 数据传输示意图)
[4.4.1.2 滑动窗口](#4.4.1.2 滑动窗口)
[4.4.1.3 超时重传机制](#4.4.1.3 超时重传机制)
[4.4.1.3.1 第一种情况:ACK丢失](#4.4.1.3.1 第一种情况:ACK丢失)
[4.4.1.3.2 第二种情况:数据包丢失](#4.4.1.3.2 第二种情况:数据包丢失)
[4.4.2 流量控制](#4.4.2 流量控制)
[4.4.3 拥塞控制](#4.4.3 拥塞控制)
[4.4.4 延时应答](#4.4.4 延时应答)
[4.4.5 捎带应答](#4.4.5 捎带应答)
1. 开发中常见的数据组织格式
1.1 XML
-
XML属于较早时期组织数据的格式,通过标签来组织数据;
-
可以认为HTML是XML的变种,HTML的标签是规定好的,不允许程序员自创;
而XML的标签都是程序员自定义的。
以某请求为例:
XML
<request>
<userId> 1000 </userId>
<position> 100,30 </position>
</request>
- XML的优势:可读性强;
XML的劣势:标签编写非常繁琐,传输时也会占用更多网络带宽;
- 目前阶段,在maven项目中会使用XML管理项目配置。
1.2 JSON
-
JSON是当前最流行的一种数据组织格式。
-
JSON是一种键值对结构,用一个{ }包裹所有键值对,如:
XML
{
userId:"1000",
position:"100, 30"
}
其中,键值对之间用逗号分割,键与值之间用冒号分割,键为String类型(键的双引号可以省略),值可以为数字、字符串、JSON、数组等等;
- JSON的优势:可读性强,比XML更简洁;
JSON的劣势:在网络传输中会消耗额外的带宽(key也需传输);
1.3 Protobuf
-
相比与json与xml,Protobuf(pb)是使用二进制的方式来组织数据的;
-
pb相当于把要传递的信息按照二进制形式压缩了,故而可以保证带宽占用最低;
-
pb的优势:占用带宽最低,传输效率最高,非常适合对于性能要求较高的场景;
pb的劣势:可读性较差,一定程度上影响开发的效率;
2. 端口号
在编写一个服务器时,必须手动指定一个端口号,以区分当前主机上的不同应用程序;
在编写一个客户端时,系统会在客户端通信时自动分配一个端口号;
端口号长度固定为2字节,能表示的数据范围为0~65535,一般来说0是不使用的,其中:
(1)1~1023:熟知端口号,给一些知名服务器预留的端口号
如:22:SSH服务器(远程登录主机); 80:HTTP服务器; 443:HTTPS服务器
(2)1024~49151:登记端口号,要使用这类端口号必须在IANA按照规定的手续登记;
(3)49152~65535:短暂端口号,客户进程运行时进行动态选择,客户进程时临时使用;
3. UDP协议
-
特点:无连接,不可靠,面向数据报,全双工;
-
报文格式:
(1)UDP报文长度字段为16位,能表示的数据范围为0~65535,即64Kb,故而使用UDP时很难表示一个很大的数据报;,当传输较大数据时会发生截断;
(2)常用的校验方法有:CRC冗余校验、MD5、SHA1算法等;
- 基于UDP的应用层协议有:
(1)NFS:网络文件系统;
(2)TFTP:简单文件传输协议;
(3)DHCP:动态主机配置协议;
(4)BOOTP:启动协议(用于无盘设备启动);
(5)DNS:域名解析协议;
4. TCP协议
4.1 特点
-
有连接,
-
面向字节流,
-
全双工:
体现在代码中:
- 可靠传输:(TCP最核心的特性)
TCP保证可靠传输是以确认应答为核心,借助其他机制辅助,最终完成可靠传输;
TCP实现可靠传输的核心机制有:
(1)确认应答:
发送方发送数据后,接收方收到数据则返回一个应答报文(acknowledge,ack);
发送方收到应答报文就知道数据是否发送成功。
(2)超时重传:
在TCP传输过程中,丢包可能出现传输数据丢失和返回的ack丢失两种情况,
但在发送方端是无法辨别的,但无论是出现了哪种情况,发送方都会进行重新传输。
重传操作大幅度提升了数据传输成功的概率,是重要的丢包补救措施。
(3)连接管理:
连接管理即建立连接(三次握手)和释放连接(四次挥手);
4.2 TCP报文格式
(1)TCP数据报=首部(报头)+数据载荷。其中报头长度不固定:
当选项部分不存在时,报头最短,为20字节;
当选项选中且长度最长(40字节)时,报头最长,为60字节。
(2)首部(4位),表示的范围为0~15,单位为4字节;
即当首部为0xF(15)时,表示首部长度为15×4字节=60字节,达到首部最大长度;
4.3 TCP可靠性机制
4.3.1 确认应答机制
注:(1)在TCP报文首部中,有一个ACK字段值为1时,该数据报中的"确认序号字段"有效;
当ACK字段为0时,表示当前数据报中的"确认序号字段"无效;
(2)TCP是按照字节进行编号(序列号)的:
4.3.2 超时重传机制
4.3.2.1 丢包的两种情况
对于第二种ACK丢失的情况,站在主机B的角度收到了2条数据,会不会导致bug是需要思考的问题。
TCP设置了一个接收缓冲区,在该内存空间中保存已经收到的数据及数据的序号。
如果接收方发现当前发送方发来的数据已经在缓冲区中存在,则判定为重复发送,直接将其丢弃。确保应用程序read时只能读到一条数据。
且接受缓冲区除去重外,还可进行重新排队。保证发送的顺序和应用程序读取的顺序是一致的。
4.3.2.2 重传时间
发送方发送数据后会进行等待,如果在等待时间内收到对方的ACK,则视为数据成功送达;
如果超过了等待时间,还没有收到ACK,就会触发重传机制。
(1)超时时间的设定并不简单,如果超时时间设的太长,会影响整体的重传效率;如果超时时间设的太短,有可能会频繁发送重复的包;
(2)初始等待时间是可以进行配置的,不同系统上的等待时间也不一定相同,可以通过修改内核参数来进行修改;
(3)等待的时间也会动态变化,超时次数越多,下一次等待时间会变长。但也不是无限变长,重传若干次则视为不可达,触发TCP的重置连接,即放弃此条连接。
(4)在Linux和Windows中,超时以500ms为一个单位进行控制,每次判定超时重发的超时时间都是500ms的整数倍。比如,重发一次后仍然没有得到应答,就会等待2*500ms后再进行重传。累积到一定次数后,TCP认为网络或对端主机出现异常,强制关闭连接。
4.3.3 连接管理机制
4.3.3.1 三次握手建立连接
- A还要发送第三次确认的意义在于:
可以防止已失效的连接请求报文段突然又传送到了B,因而产生错误。
- 三次握手的核心作用:
(1)确认当前网络是否通畅;
(2)发送方和接收方确认自己发送能力与接受能力正常;
(3)让通信双方在握手过程中针对一些重要参数进行协商,如通信数据的开始序号;
4.3.3.2 四次挥手释放连接
- 四次挥手中间的两次交互不一定能合二为一,这与三次握手建立连接不同。
(1)对于三次握手:
ACK与第二个SYN都是内核触发的,同一个时机可以合并;
(2)对于四次挥手:
ACK与第二个FIN的触发时机是不同的:
ACK是内核触发的,B收到FIN就会立刻返回ACK;
第二个FIN是应用程序的代码触发,B方调用close方法才会触发FIN;
从服务器收到FIN并发送ACK后,再到执行close发起FIN中间要经历多少时间是不确定的。
4.3.3.3 建立连接与释放连接的总过程
注:TIME_WAIT状态需要等待2MSL(最长报文段寿命)存在的意义:
(1)假如没有设置TIME_WAIT状态而令A直接进入关闭状态,如果最后一个ACK丢失了,B会超时重传FIN,而A已经释放连接,则重传的FIN就无法被A收到。
而设置了TIME_WAIT状态后,如果对方重传了FIN,A就可以继续返回ACK了。
即:保证最后一个ACK能够到达对方。
(2)防止已失效的连接请求报文段出现在本连接中,A发送完最后一个ACK后再经过2MSL,就可以使本连接持续时间内所产生的所有报文段都从网络中消失。
4.4 TCP效率提高机制
4.4.1 滑动窗口协议
已知TCP的可靠传输会影响传输的效率,故而提出了滑动窗口协议用于尽可能降低可靠传输对性能的影响;
对于一发一收传输方式:
这种传输方式的等待时间是较长的;
批量传输方式:
4.4.1.1 数据传输示意图
无需等待ACK返回直接发送下一个数据。设置一个批量发送数据的最大限度,达到上限后再同意等待ACK。将这个数据量上限称为窗口大小。
4.4.1.2 滑动窗口
(1)当前A向B批量发送了4份数据,达到发送窗口大小,停止发送,等到B的ACK;
(2)B收到A的4份数据后,向A发送4个ACK;
(3)当A收到B对第一份数据的ACK后,就将窗口滑动,继续发送第五份数据;
4.4.1.3 超时重传机制
4.4.1.3.1 第一种情况:ACK丢失
此种情况无需重传。
确认序号表示当前序号之前的数据已经全部接收到了,下一个希望收到当前序号的数据包。
故而如果1001的ACK丢失了,而2001的ACK成功返回则表示2001号之前的数据都已经传输成功了,包括了1001ACK的含义。称为累积确认。
4.4.1.3.2 第二种情况:数据包丢失
(1)当主机B向A发送1001号ACK时,表示下一个希望收到1001及以后得数据包;
(2)主机A发送给主机B的1001~2000号数据包丢失,故而主机B未收到期待序号的数据包。主机B无论主机A继续发送什么序号的数据包都不予确认,而是连续发送三个重复确认ACK,向主机A索要1001号数据包;
(3)当主机A收到主机B发来的连续重复确认后,就开始重传1001~2000号数据包。
(4)当主机B成功接收1001~2000号数据包后,对这段时间主机A所发送的多条数据包进行累积确认,即发送7001号ACK;
注:
(1)上述重传操作中,并没有额外的冗余操作,哪个数据丢失就重传哪个,没有丢失的无需重传,整个过程比较迅速,称为**快速重传,**是滑动窗口协议下的对超时重传机制的变种。
(2)如果通信双方传输数据量较小,也不频繁,就仍然是普通的确认应答和普通的超时重传;
如果通信双方传输数据量较大,也较频繁,就会进入滑动窗口模式,进行快速重传的方式处理。
4.4.2 流量控制
流量控制即:根据接收方的接受速率,控制发送方的发送速率。
避免出现发送方发送太快导致接收方来不及接收的情况。
(1)主机A向主机B发送数据后,数据先到达B的系统内核中。TCP socket对象上带有接收缓冲区,A发送给B的数据就会先到达B的接收缓冲区;
(2)B的应用程序会调用read这样的方法,把数据从接收缓冲区中读出来进行进一步的处理。
一旦数据被read了,就可以从缓冲区删除了;
注:(1)对应TCP报文格式,其中的"16位窗口大小"用于表示接收缓冲区剩余空间大小。但此处空间最大值并非64K,在TCP报头中的选项部分有一项叫做"窗口扩展因子",可以对窗口大小进行左移位,从而表示更大的范围;
(2)TCP规定,即使接收窗口为0,也必须接收窗口探测报文、确认报文段以及携带紧急数据的报文段;
4.4.3 拥塞控制
- 拥塞控制即:防止过多的数据注入到网络中,使网络中的路由器或链路不至于过载,是一个全局性的问题;
而流量控制往往是指点对点通信量的控制,是个端到端的问题。
注:(1)在TCP建立连接和网络出现超时时,采用慢开始和拥塞避免算法,当发送方接收到冗余ACK时,采用快重传和快恢复算法。
(2)流量控制和拥塞控制都是在限制发送方窗口的大小,最终发送的窗口大小为流量控制与拥塞控制窗口中的较小值;
4.4.4 延时应答
- 正常情况下,A把数据传输给B,B就会立即返回ACK给A;
但有的时候A传输给B,B等待一段时间后再向A返回ACK,此时就是延时应答;
- 比如在流量控制中,可以使用延时返回ACK,以给接收方更多的时间来读取接收缓冲区的数据,缓冲区的空间会更大,使得可以返回的窗口大小也增大了。
4.4.5 捎带应答
由于TCP延时应答的存在,有可能存在以下情况:
(1)ACK是内核立即返回的,response是应用程序代码返回的,二者时机是不同的;
(2)TCP引入延时应答后,B对A的ACK可能不是立即返回,在其延时返回的过程中,可能B就计算好response,此时就可以将业务数据response捎带ACK进行返回:
(3)将两个数据包合二为一个数据包进行发送,可以实现更高效地传输;