文章目录
TCP 协议如何保证可靠传输
先看看这张图:TCP头部结构图
TCP协议保证数据传输可靠性的方式主要有:
- 校验和
- 序列号
- 确认应答
- 超时重传
- 连接管理
- 流量控制
- 拥塞控制
校验和
TCP校验和是一个端到端的校验和,由发送端计算,然后由接收端验证。其目的是为了发现TCP首部和数据在发送端到接收端之间发生的任何改动。如果接收方检测到校验和有差错,则TCP段会被直接丢弃。
TCP在计算校验和时,会在TCP首部加上一个12字节的伪首部。检验和总共计算3部分:TCP首部
、TCP数据
、TCP伪首部
注意区别:
- TCP校验和覆盖TCP首部和TCP数据
- IP首部中的校验和只覆盖IP的首部,不覆盖IP数据报中的任何数据
- TCP的校验和是必需的,而UDP的校验和是可选的。
- TCP和UDP计算校验和时,都要加上一个12字节的伪首部。
计算方式:在数据传输的过程中,将发送的数据段都当做一个16位的整数,将这些整数加起来,并且前面的进位不能丢弃,补在后面
,最后取反,得到校验和。
发送方:在发送数据之前计算检验和,并进行校验和的填充。
接收方:收到数据后,对数据以同样的方式进行计算,求出校验和,与发送方的进行比对。
序列号/确认应答
序列号:TCP传输时将每个字节的数据都进行了编号,这就是序列号。
确认应答:TCP传输的过程中,每次接收方收到数据后,都会对传输方进行确认应答。也就是发送ACK报文。这个ACK报文当中带有对应的确认序列号,告诉发送方,接收到了哪些数据,下一次的数据从哪里发。
上述过程中,只要发送端有一个包传输,接收端没有回应确认包(ACK包),都会重发,或者接收端的应答包,发送端没有收到也会重发数据。这就可以保证数据的完整性。
超时重传
在进行TCP传输时,由于确认应答与序列号机制,也就是说发送方发送一部分数据后,都会等待接收方发送的ACK报文,并解析ACK报文,判断数据是否传输成功。如果发送方发送完数据后,迟迟没有等到接收方的ACK报文,这该怎么办呢?而没有收到ACK报文的原因可能是什么呢?
首先,发送方没有接收到响应的ACK报文原因可能有两点:
- 数据在传输过程中由于网络原因等直接
全体丢包
,接收方根本没有接收到。 - 接收方接收到了响应的数据,但是发送的ACK报文
响应
却由于网络原因丢包
了。
TCP在解决这个问题的时候引入了一个新的机制,叫做超时重传机制:
- 简单理解就是发送方在发送完数据后等待一个时间,时间到达没有接收到ACK报文,那么对刚才发送的数据进行重新发送。
- 如果是刚才第一个原因,接收方收到二次重发的数据后,便进行ACK应答。
- 如果是第二个原因,接收方发现接收的数据已存在(
判断存在的根据就是序列号,所以上面说序列号还有去除重复数据的作用
),那么直接丢弃,仍旧发送ACK应答。
那么发送方发送完毕后等待的时间是多少呢?如果这个等待的时间过长,那么会影响TCP传输的整体效率,如果等待时间过短,又会导致频繁的发送重复的包。如何权衡?
由于TCP传输时保证能够在任何环境下都有一个高性能的通信,因此这个最大超时时间(也就是等待的时间)是动态计算
的。
- 在Linux中(BSD Unix和Windows下也是这样)超时以500ms为一个单位进行控制,每次判定超时重发的超时时间都是500ms的整数倍。
- 重发一次后,仍未响应,那么等待2500ms的时间后,再次重传。等待4500ms的时间继续重传。
- 以一个指数的形式增长。累计到一定的重传次数,TCP就认为网络或者对端出现异常,强制关闭连接。
连接管理
连接管理就是三次握手与四次挥手的过程,我们在后面会详述。
连接管理保证可靠的连接,是保证可靠性的前提。
流量控制
接收端在接收到数据后,对其进行处理。如果发送端的发送速度太快
,导致接收端的结束缓冲区
很快的填充满了。此时如果发送端仍旧发送数据,那么接下来发送的数据都会丢包,继而导致丢包的一系列连锁反应,超时重传呀什么的。
TCP根据接收端对数据的处理能力,决定发送端的发送速度,这个机制就是流量控制
。
在TCP协议的报头信息当中,有一个16位字段的窗口大小。在介绍这个窗口大小时我们知道,窗口大小的内容实际上是接收端接收数据缓冲区的剩余大小
。这个数字越大,证明接收端接收缓冲区的剩余空间越大,网络的吞吐量越大。接收端会在确认应答发送ACK报文时,将自己的即时窗口大小填入,并跟随ACK报文一起发送过去
。而发送方根据ACK报文里的窗口大小的值的改变进而改变自己的发送速度。
如果接收到窗口大小的值为0,那么发送方将停止发送数据。并定期的向接收端发送窗口探测数据段
,让接收端把窗口大小告诉发送端。
注:
- 16位的窗口大小最大能表示65535个字节(64K),但是TCP的窗口大小最大并不是64K。
- 在TCP首部中40个字节的选项中还包含了一个窗口扩大因子M,实际的窗口大小就是16位窗口字段的值左移M位。
- 每移一位,扩大两倍。
拥塞控制
TCP传输的过程中,发送端开始发送数据的时候,如果刚开始就发送大量的数据,那么就可能造成一些问题。网络可能在开始的时候就很拥堵,如果给网络中在扔出大量数据,那么这个拥堵就会加剧。拥堵的加剧就会产生大量的丢包,就会产生大量的超时重传,严重影响传输。
所以TCP引入了慢启动的机制
,在开始发送数据时,先发送少量的数据探路
,探清当前的网络状态如何,再决定多大的速度进行传输。
这时候就引入一个叫做拥塞窗口的概念,发送刚开始定义拥塞窗口为 1,每次收到ACK应答,拥塞窗口加 1,在发送数据之前,首先将拥塞窗口与接收端反馈的窗口大小比对,取较小的值作为实际发送的窗口。
拥塞窗口的增长是指数级别的
。慢启动的机制只是说明在开始的时候发送的少,发送的慢,但是增长的速度是非常快的。
为了控制拥塞窗口的增长,不能使拥塞窗口单纯的加倍,设置一个拥塞窗口的阈值,当拥塞窗口大小超过阈值时,不能再按照指数来增长,而是线性的增长。
在慢启动开始的时候,慢启动的阈值等于窗口的最大值
(注意:不是刚开始的值,是第一次的阈值),一旦造成网络拥塞,发生超时重传时,慢启动的阈值会变为发生网络拥塞时拥塞窗口的大小
的一半(注意:不是原来阈值的一半),同时拥塞窗口重置为 1。
TCP 三次握手和四次挥手
先看看这张图:TCP头部结构图
TCP协议概述
TCP全称为传输控制协议
,这是传输层
的一个协议,对数据的传输进行一个详细的控制。
特点:
面向字节流
安全可靠
面向连接
三次握手和四次挥手的简单回答
握手:TCP连接
三次握手的本质是确认通信双方(Client端、Server端)
收发数据的能力
挥手:TCP断开
三次握手
第一次握手:客户端请求连接服务器响应,向服务器发送同步报文段也就是SYN请求,发送完毕后等待服务器响应。
第二次握手:服务器请求客户端响应,服务器如果收到了SYN同步报文段,那么就会给客户端发送ACK响应,意为收到了客户端发送的同步报文段,在此同时,服务器也会发送SYN同步报文段,请求客户端的响应。
第三次握手:客户端在接收到SYN同步报文段后也会发送ACK响应来回复服务器。
以上这个过程就是三次握手的过程,如下图:
这样看来,客户端与服务器的连接是双方的
,两者都得发送请求同样两者也都得响应。
图上来看,SYN_SENT
就是请求连接状态,SYN_RCVD
就是等待连接状态,在三次握手成功后,服务器与客户端都会进入ESTABLISHED
状态,也就是TCP连接成功态,这个时候就可以进行数据的传送了。
这个过程中如果客户端的SYN请求如果丢包,服务器不会响应,而客户端会有一个等待时间,等待时间到达,未收到ACK响应,这个时候客户端会发起再次请求,如果多次请求都未成功,此时客户端可能会判断网络异常,不会再次请求。
同样再服务器接收到客户端的SYN请求之后也会发送ACK响应同时发送SYN请求,如果客户端迟迟不给服务器ACK响应,服务器也会进行重发,直至判断网络异常。
所以说,三次握手任意一个缺失都不会连接成功,也就无法通信。所以三次握手也是确保TCP可靠的一种方式。
四次挥手
第一次挥手:在客户端与服务器数据传输完毕之后,客户端没有请求了,所以此时调用close关闭文件描述符,开始进入FIN_WAIT_1状态,同时向服务器发送FIN结束报文段
,等待服务器的响应。
第二次挥手:当服务器这里收到了FIN结束报文段时,这个时候,服务器进入CLOSE_WAIT状态,并向客户端进行应答发送ACK应答报文
。
第三次挥手:当客户端收到服务器的ACK响应时,进入FIN_WAIT_2状态,由于可能有没传输完成的数据,当数据传输完成,服务器调用close时,会向客户端发送FIN结束报文段
,此时进入LAST_ACK状态。
第四次挥手:此时的客户端收到服务器发送的FIN结束报文时,会向服务器进行响应ACK
,并且客户端进入TIME_WAIT状态,当服务器收到客户端最后的ACK时,进入CLOSED状态,断开连接成功,客户端TIME_WAIT结束之后,进入CLOSED,断开连接成功。
以上这个过程就是四次挥手的过程,如下图:
为什么连接的时候是三次握手,关闭的时候却是四次握手?
连接的时候,服务器可以将SYN与ACK同时发送
。
断开的时候,服务器将FIN与ACK分开发送
。
为什么要这样??
- 首先FIN信号是由于
调用close
所以才发送的,而客户端调用close时,发送FIN结束报文段并进入FIN_WAIT_1状态。 - 而这个报文段在服务器中用户态其实是无法感知的,内核会自己处理这个报文段,也就是说由内核进行ACK响应,这个过程中不是由用户代码决定的,服务器的FIN是由用户代码调用close发送的,所以内核与服务器不一定是同时处理这个信息的,所以FIN与ACK
不一定是同时发送出去的
。 - 注意:这里是不一定!!!但是三次握手的时候发送SYN是由内核直接完成的,所以这就可以达到一个同步发送的情况。
如果服务器的代码没有调用close,那么意味着并没有发送FIN结束报文段。那么也就是说,此连接的服务器长期保持在CLOSE_WAIT状态,这会有什么影响?
- 服务器长期保持在CLOSE_WAIT状态,也就是说分配的文件描述符并没有关闭并归还。
- 那么大量的CLOSE_WAIT存在的话,就会导致一种资源的泄漏。可能到最后就没有可分配的文件描述符了,那么就会使一些客户端无法连接,从而造成不可估量的影响。
为什么要TIME_WAIT
在客户端最后一次发送ACK响应后,进入TIME_WAIT状态,而这个状态的时候客户端在做什么呢?
答案就是等待!
客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL,这么做有两个理由:
-
确保ACK报文能够到达服务端。如果服务端没收到客户端发送来的确认报文,那么就会重新发送FIN报文给客户端,客户端等待一段时间就是为了处理这种情况的发生。
-
等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。
注意:
-
如果服务器主动断开连接,也就是主动关闭服务器,如果有TCP连接着服务器,服务器会进入
TIME_WAIT
状态,这时候接着再次启动服务器,发现启动不了,启动不了的原因是端口号绑定失败。 -
其实这就是因为在TIME_WAIT状态的时候,TCP连接还是存在的,那么刚才的端口号仍旧被绑定着,再次启动服务器的时候,此时的端口号并未被释放,所以才提示绑定失败。
-
如果服务器需要处理大量的客户端连接,每个连接的生存时间很短,但是每秒都有大量的客户端请求。这个时候如果服务器主动关闭连接,就会产生大量的TIME_WAIT连接。由于我们的需求量很大,就会导致TIME_WAIT的连接数很多,从而导致服务器的端口不够用,无法处理新的连接。这个时候如何解决呢?
这时候可以利用函数setsockopt()来解决这个问题,这个函数的作用就是允许创建端口号相同但是IP地址不同的多个socket描述符。在socket()与bind()之间调用即可。
如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP设有一个保活计时器,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。
服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。
若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
TCP 粘包产生原因以及解决方法
TCP头部结构图
UDP头部结构图
为什么会出现TCP 粘包
TCP属于传输层的协议,传输层除了有TCP协议
外还有UDP协议
。
UDP是否会发生粘包或拆包的现象呢?
- 答案是不会。
UDP是基于报文
发送的,从UDP的帧结构
可以看出,在UDP首部采用了16bit
来指示UDP数据报文的长度,因此在应用层
能很好的将不同的数据报文
区分开,从而避免粘包和拆包的问题。
TCP是基于字节流
的,虽然应用层
和TCP传输层
之间的数据交互是大小不等的数据块
,但是TCP把这些数据块仅仅看成一连串无结构的字节流
,没有边界,另外从TCP的帧结构
也可以看出,在TCP的首部没有表示数据长度的字段,基于上面两点,在使用TCP传输数据时,才有粘包或者拆包现象发生的可能。
何为面向字节流
创建一个socket,不仅仅只是申请一个文件描述符,并且还开辟一片发送缓冲区
及接收缓冲区
。
在调用write进行写数据时,先写入发送缓冲区当中,如果数据较大,那么TCP进行分包发送
,如果数据较小,那么就先在发送缓冲区内部等待,等到了合适的时候再发出。
在接收数据时,首先将数据读至接收缓冲区,接着调用read进行读数据,由于TCP既有发送缓冲区又有接收缓冲区,所以write与read并不冲突,可同时进行,这个就叫做全双工
。
在进行读写的时候,不用一次性读完或写完,可以分批来,这也是面向字节流的好处。
什么是粘包、拆包?
由于TCP是面向字节流的,并且在发送时候,先写入到发送缓冲区内部,但是在发送缓冲区内部不一定发送,如果数据过小会等待接下来的数据,如果过大就分包,这就造成了粘包的问题。
例举一下几种形式如下:
- 第一种情况:接收端正常收到两个数据包,即没有发生拆包和粘包的现象。
- 第二种情况:接收端只收到一个数据包,但是这一个数据包中包含了发送端发送的
两个数据包的信息
,这种现象即为粘包,这种情况由于接收端不知道这两个数据包的界限,所以对于接收端来说很难处理。
- 第三种情况:这种情况有两种表现形式,如下图,接收端收到了两个数据包,但是这两个数据包要么是不完整的,要么就是多出来一块,这种情况即发生了
拆包和粘包
,这两种情况如果不加特殊处理,对于接收端同样是不好处理的。
粘包产生的常见原因
发生TCP粘包或拆包有很多原因,列出常见原因:
-
要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。
-
待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。
-
要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包。
-
接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。
粘包的解决方法
解决粘包问题的核心就是明确两个包的界限
!!!
由于 TCP 本身是面向字节流的,无法理解上层的业务数据,所以在底层是无法保证数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决,根据业界的主流协议的解决方案,归纳如下:
-
消息定长:发送端将每个数据包封装为固定长度(不够的可以通过补 0 填充),这样接收端每次接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
-
设置消息边界:服务端从网络流中按消息边界分离出消息内容。在包尾增加回车换行符进行分割,例如 FTP 协议。
-
将消息分为消息头和消息体:消息头中包含表示消息总长度(或者消息体长度)的字段。
基于TCP/UDP协议的应用层协议有哪些
协议有很多,我们只讨论基于TCP/UDP协议的应用层协议,因为这些是最常用的协议!!!
先看一下TCP/IP四层协议模型:
TCP/UDP都是传输层的协议
(上面是应用层
,下面是网际层)
基于TCP的应用层协议常用的有:HTTP
、FTP
、SMTP
、TELNET
、SSH
协议 | 全称 | 默认端口 |
---|---|---|
HTTP ( 用的最多) | HyperText Transfer Protocol(超文本传输协议) | 80 |
FTP | File Transfer Protocol (文件传输协议) | 20用于传输数据,21用于传输控制信息 |
SMTP | Simple Mail Transfer Protocol (简单邮件传输协议) | 25 |
TELNET | Teletype over the Network (网络电传) | 23 |
SSH | Secure Shell | 22 |
基于UDP的应用层协议:DNS
、TFTP(简单文件传输协议)
、SNMP(简单网络管理协议)
协议 | 全称 | 默认端口 |
---|---|---|
DNS | Domain Name Service (域名服务) | 53 |
TFTP | Trivial File Transfer Protocol (简单文件传输协议) | 69 |
SNMP | Simple Network Management Protocol (简单网络管理协议) | 通过UDP端口161接收,只有Trap信息采用UDP端口162。 |
NTP | Network Time Protocol (网络时间协议) | 123 |
TCP和UDP的区别是什么?
UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息。
优点:UDP速度快、操作简单、要求系统资源较少,由于通讯不需要连接,可以实现广播发送
缺点:UDP传送数据前并不与对方建立连接,对接收到的数据也不发送确认信号,发送端不知道数
据是否会正确接收,也不重复发送,不可靠。
TCP是面向连接的通讯协议,通过三次握手建立连接,通讯完成时四次挥手
优点:TCP在数据传递时,有确认、窗口、重传、阻塞等控制机制,能保证数据正确性,较为可靠。Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。
缺点:TCP相对于UDP速度慢一点,要求系统资源较多。
HTTP 与 HTTPS 协议
概述
HTTP协议(超文本传输协议):被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容
,不提供任何方式的数据加密
,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。
为了解决HTTP协议的这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS,为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议
,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
HTTP和HTTPS的基本概念
HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版
,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
总结就是:
-
HTTP协议运行在TCP之上,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份。
-
HTTPS是HTTP运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输的内容都经过加密,加密采用
对称加密
,但对称加密的密钥用服务器方的证书
进行了非对称加密。此外客户端可以验证服务器端的身份,如果配置了客户端验证,服务器方也可以验证客户端的身份。
HTTP与HTTPS有什么区别?
区别 | HTTP | HTTPS |
---|---|---|
协议 | 运行在 TCP 之上,明文传输,客户端与服务器端都无法验证对方的身份 | 身披 SSL外壳的 HTTP,运行于 SSL 上,SSL 运行于 TCP 之上, 是添加了加密和认证机制的 HTTP。 |
端口 | 80 | 443 |
资源消耗 | 较少 | 由于加解密处理,会消耗更多的 CPU 和内存资源 |
开销 | 无需证书 | 需要证书,而证书一般需要向认证机构购买 |
加密机制 | 无 | 共享密钥加密和公开密钥加密并用的混合加密机制 |
安全性 | 弱 | 由于加密机制,安全性强 |
HTTPS的工作原理
我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取,所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议。
客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤,如图所示。
1、客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
2、Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
3、客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
4、客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给Web服务器。
5、Web服务器利用自己的私钥解密出会话密钥。
6、Web服务器利用会话密钥加密与客户端之间的通信。
HTTPS的优缺点
优点:
-
(1)使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
-
(2)HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。
-
(3)HTTPS是现行架构下最安全的解决方案,
虽然不是绝对安全
,但它大幅增加了中间人攻击的成本。 -
(4)谷歌曾在2014年8月份调整搜索引擎算法,并称比起同等HTTP网站,采用HTTPS加密的网站在搜索结果中的排名将会更高。
缺点
-
(1)HTTPS协议握手阶段比较费时,会使页面的加载时间延长近50%,增加10%到20%的耗电;
-
(2)HTTPS连接缓存不如HTTP高效,会增加数据开销和功耗,甚至已有的安全措施也会因此而受到影响;
-
(3)SSL证书需要钱,功能越强大的证书费用越高,个人网站、小网站没有必要一般不会用。
-
(4)SSL证书通常需要绑定IP,不能在同一IP上绑定多个域名,IPv4资源不可能支撑这个消耗。
-
(5)HTTPS协议的加密范围也比较有限,在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么作用。最关键的,SSL证书的信用链体系并不安全,特别是在某些国家可以控制CA根证书的情况下,中间人攻击一样可行。