客户主机发起链接请求,设置SYN
标志位为1
,同时客户端随机
选择了一个初始序号client_isn
,而且存放在TCP报文
字段的序号
中css
接下来,当服务端接收到该报文后,会为其分配TCP 缓存和变量
(这使得TCP容易受到被称为SYN 洪泛攻击
的拒绝服务攻击)紧接着,服务端会返回一个SYNACK 报文
到客户端,其中SYN
标志位为1
,确认号
设置为client_isn + 1
,而且选一个本身的初始序号server_isn
,并放置在序号
字段中html
当收到服务器发来的SYNACK
报文段后,客户端也须要给该链接分配缓存和变量,而后再次发送一个确认报文给服务端,其中,SYN
标志位设置为0
,将确认号
设置为server_isn + 1
,另外,这次报文能够携带负载数据java
简单来讲,三次握手的目的是为了让双方验证各自的接收能力和发送能力。算法
SYN
到B
,B
接收到了后,能确认什么呢? 显然,B
能确认A
的发送
能力和B
的接收
能力;B
发送SYNACK
到A
,A
接收到后,能确认什么呢? A
能确认B
的发送能力和A
本身的接收能力,此外,A
收到了SYNACK
,那么说明前面A
发的SYN
成功到达B
的手中,因此也能确认A
本身的发送
能力和B
的接收
能力;至此,A
已经确认了双方各自的发送能力和接收能力都是OK
的,所以转为ESTABLISHED
状态;A
发送ACK
到B
,B
接收后,能确认什么呢? B
能确认A
的发送
能力和B
的接收
能力,另外因为B
能收到ACK
说明前面发送的SYNACK
已经成功被接受了,说明能确认A
的接收
能力和B
的发送
能力。若是使用两次握手,就不能确认上述所说的四种能力,那么就会致使问题。编程
假定不采用第三次报文握手,那么只要B发出确认,新的链接就创建了。浏览器
现假定一种异常状况,即A
发出的SYN
报文段并无丢失,而是在某些网络节点长时间滞留了,以至延误到链接释放后的某个时间才到达B
。原本这是一个早已失效的报文段。但B
收到此失效的链接请求报文段后,却误觉得是A
又发出一次新的链接请求,因而就向A
发出确认报文段,赞成创建链接。缓存
因为如今A
并无发出创建链接的请求,所以不会理睬B
的确认,也不会向B
发送数据,但B
却觉得新的运输链接已经创建了,并一直等待A
发来的数据。B
的许多资源就这样白白浪费了。服务器
ACK报文丢失致使第三次握手失败网络
当客户端收到服务端的SYNACK
应答后,其状态变为ESTABLISHED
,并会发送ACK
包给服务端,准备发送数据了。若是此时ACK
在网络中丢失(如上图所示),过了超时计时器后,那么服务端会从新发送SYNACK
包,重传次数根据/proc/sys/net/ipv4/tcp_synack_retries
来指定,默认是5
次。若是重传指定次数到了后,仍然未收到ACK
应答,那么一段时间后,Server
自动关闭这个链接。并发
问题就在这里,客户端已经认为链接创建,而服务端则可能处在SYN-RCVD
或者CLOSED
,接下来咱们须要考虑这两种状况下服务端的应答:
CLOSED
,当接收到链接已经关闭的请求时,服务端会返回RST 报文
,客户端接收到后就会关闭链接,若是须要的话则会重连,那么那就是另外一个三次握手了。SYN-RCVD
,此时若是接收到正常的ACK 报文
,那么很好,链接恢复,继续传输数据;若是接收到写入数据等请求呢?注意了,此时写入数据等请求也是带着ACK 报文
的,实际上也能恢复链接,使服务器恢复到ESTABLISHED
状态,继续传输数据。不固定,client_isn
是随机生成的,而server_isn
则须要根据SYN 报文
中的源、ip和端口
,加上服务器自己的密码数
进行相同的散列获得,显然这也不是固定的。
第三次握手是能够携带数据的
,而前两次不行。
首先,当前客户端和服务器的状态都为ESTABLISHED
客户主机发起链接释放的请求,设置FIN
为1
,固然,序号seq
也会带上,这里假设为u
;发送完毕后,客户端进入 FIN-WAIT-1
状态
服务端接收到FIN 报文
后,会返回一个ACK 报文
回去,此时设置ACK
为1
,确认号
为u + 1
;代表本身接受到了客户端关闭链接的请求,但尚未准备好关闭链接。发送完毕后,服务器端进入 CLOSE-WAIT
状态,客户端接收到这个确认包以后,进入 FIN-WAIT-2
状态,等待服务器端关闭链接
服务器端准备好关闭链接时,向客户端发送结束链接请求,FIN
置为1
;发送完毕后,服务器端进入 LAST-ACK
状态,等待来自客户端的最后一个ACK
客户端接收到服务端传来的FIN 报文
后,知道服务器已经准备好关闭了,发送一个确认包,并进入 TIME-WAIT
状态,等待可能出现的要求重传的ACK 报文
;服务器端接收到这个确认包以后,关闭链接,进入 CLOSED
状态。
客户端等待了某个固定时间(两个最大段生命周期,2MSL
,2 Maximum Segment Lifetime)以后,没有收到服务器端的 ACK
,认为服务器端已经正常关闭链接,因而本身也关闭链接,进入 CLOSED
状态
TIME-WAIT
状态,为何须要这个状态呢?要确保服务器是否已经收到了咱们的ACK 报文
,若是没有收到的话,服务器会从新发FIN 报文
给客户端,那么客户端再次收到FIN 报文
以后,就知道以前的 ACK 报文
丢失了,就会再次发送ACK 报文
。
关键就在中间两步。
SYN 报文
后,能够直接发送SYNACK 报文
。其中ACK
是用来应答的,SYN
是用来同步的。FIN 报文
时,极可能并不会当即关闭SOCKET
,因此只能先回复一个ACK 报文
,告诉客户端,“你发的FIN 报文
我收到了”。只有等到服务器全部的报文都发送/接收完了,我才能发送FIN 报文
,所以不能一块儿发送,须要四次握手ACK 报文
可以到达服务器。咱们必须假设网络是不可靠的,ACK 报文
可能丢失。若是服务端发出FIN 报文
后没有收到ACK 报文
,就会重发FIN 报文
,此时处于TIME-WAIT
状态的客户端就会重发ACK 报文
。固然,客户端也不能无限久的等待这个可能存在的FIN 报文
,由于若是服务端正常接收到了ACK 报文
后是不会再发FIN 报文
的。所以,客户端须要设置一个计时器,那么等待多久最合适呢?所谓的MSL
(Maximum Segment Lifetime)指一个报文在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。若是直到2MSL
时间后,客户端都没有再次收到FIN 报文
,那么客户端推断ACK 报文
已经被服务器成功接收,因此结束TCP 链接
。ACK 报文
后,再通过时间2MSL
,就可使因为网络不通畅产生的滞留报文段失效。这样下一个新的链接中就不会出现旧的链接请求报文每一个HTTP请求都要经历一次DNS解析、三次握手、传输和四次挥手。反复建立和断开TCP链接的开销巨大,在如今看来,这种传输方式简直是糟糕透顶。
人们认识到短链接的弊端,提出了持久链接的概念,在HTTP/1.0中获得了初步的支持。
持久链接,即一个TCP链接服务屡次请求:
客户端在请求header中携带Connection:
Keep-Alive,便是在向服务端请求持久链接。若是服务端接受持久链接,则会在响应header中一样携带Connection:
Keep-Alive,这样客户端便会继续使用同一个TCP链接发送接下来的若干请求。(Keep-Alive的默认参数是[timout=5,
max=100],即一个TCP链接能够服务至多5秒内的100次请求)
当服务端主动切断一个持久链接时(或服务端不支持持久链接),则会在header中携带Connection: Close,要求客户端中止使用这一链接。
HTTP/1.1开始,即便请求header中没有携带Connection: Keep-Alive,传输也会默认以持久链接的方式进行。
目前全部的浏览器都默认请求持久链接,几乎全部的HTTP服务端也都默认开启对持久链接的支持,短链接正式成为过去式。(HTTP/1.1的发布时间是1997年,最后一次对协议的补充是在1999年,咱们能够夸张地说:HTTP短链接这个概念已通过时了近20年了。)
同时,持久链接的弊端被提出 —— HOLB(Head of Line Blocking)
即持久链接下一个链接中的请求仍然是串行的,若是某个请求出现网络阻塞等问题,会致使同一条链接上的后续请求被阻塞。
因此HTTP/1.1中提出了pipelining概念,即客户端能够在一个请求发送完成后不等待响应便直接发起第二个请求,服务端在返回响应时会按请求到达的顺序依次返回,这样就极大地下降了延迟。
然而pipelining并无完全解决HOLB,为了让同一个链接中的多个响应可以和多个请求匹配上,响应仍然是按请求的顺序串行返回的。因此pipelining并无被普遍接受,几乎全部代理服务都不支持pipelining,部分浏览器不支持pipelining,支持的大部分也会将其默认关闭。
multiplexing即多路复用,在SPDY中提出,同时也在HTTP/2中实现。
multiplexing技术可以让多个请求和响应的传输彻底混杂在一块儿进行,经过streamId来互相区别。这完全解决了holb问题,同时还容许给每一个请求设置优先级,服务端会先响应优先级高的请求。
如今Chrome、FireFox、Opera、IE、Safari的最新版本都支持SPDY,Nginx/Apache HTTPD/Jetty/Tomcat等服务端也都提供了对SPDY的支持。
下面从一个真实的gRPC SayHello
请求,查看它在HTTP/2上是怎样实现的
能够看到下面这些Header:
而后请求的参数在DATA frame里:
简而言之,gGRPC把元数据放到HTTP/2 Headers里,请求参数序列化以后放到 DATA frame里
HTTP / 2 支持 HTTP / 1.1 的全部核心功能,但旨在经过多种方式提升效率
HTTP/2 将每个请求变成流,每个流都有本身的 ID,有本身的优先级,这些流能够由客户端发送到服务端,也能够由服务端发送到客户端,将数据划分为帧,头部信息为 head 帧,实体信息为 data 帧,最后将这些流乱序发送到一个 TCP 链接中,以下图:
若是服务端推送资源是呗客户端缓存过的,客户端是有权力拒绝服务端的推送的,浏览器能够经过发送 RST_STREAM 帧来拒收。
HTTP /1 的请求头较大,并且是以纯文本发送,HTTP/2 对消息头进行了压缩,采用的是 HACK 算法,可以节省消息头占用的网络流量,其主要是在两端创建了索引表,消息头在传输时能够采用索引,而 HTTP/1.x 每次请求,都会携带大量冗余头信息,浪费了不少带宽资源
gRPC 是 Google 基于 HTTP/2 以及 protobuf 的,要了解 gRPC 协议,只须要知道 gRPC 是如何在 HTTP/2 上面传输就能够了。
gRPC 一般有四种模式,unary,client streaming,server streaming 以及 bidirectional streaming,对于底层 HTTP/2 来讲,它们都是 stream,而且仍然是一套 request + response 模型。
gRPC 的 request 一般包含
Response 主要包含
HTTP-Status 就是咱们一般的 HTTP 200,301,400 这些,很通用就再也不解释。Status 也就是 gRPC 的 status, 而 Status-Message 则是 gRPC 的 message。Status-Message 采用了 Percent-Encoded 的编码方式,具体参考这里。
若是在最后收到的 HEADERS frame 里面,带上了 Trailers,而且有 END_STREAM 这个 flag,那么就意味着 response 的 EOS。
gRPC 的 service 接口是基于 protobuf 定义的,咱们能够很是方便的将 service 与 HTTP/2 关联起来。
基于 http2 协议的特性:gRPC 容许定义以下四类服务方法
这是一个编码算法,咱们都知道,int32 占四个字节,int64 占 8 个字节,这是固定的,无论这个数字是 1 仍是 123456,占的字节数是同样,那有没有一种能根据数字大小变长编码的算法呢?Base 128 varint 就是,在设置二进制网络协议通讯时,这种好处是可观的,可以带来性能上的提高。为何叫 128 呢,就是由于采用 7bit 的空间存储数据(一个字节占 8bit,但只采用 7bit),7bit 最大固然只能存储 128 了,那么最高位干啥呢?最高位用来看成一个标识 (flag), 若是最高位是 0 就表示这个最后一个字节了。
咱们用一个数字 10 和数字 300 来说解一下上面的 Base 128 varint
先说数字 10,转化为二进制后是:0000 1010,为何只有八位呢,由于 10 用一个字节表示已经足够了,最高位为 0(加粗的那个),表示这是最后一个字节了,不须要再用额外的字节来存储了
再来看数字 300,转化为二进制后是:00010010_1100, 转化成 varint,以下步骤:
按照 7 位进行分开, 0000010_0101100,不够的补 0
进行反转:0101100_0000010
最高位补数,第一个字节最高位补 1,第二个字节最高位补 0:10101100_00000010
Tag,Length,Value ,这是序列化后存储的二进制的格式,Tag 你们简单理解为就是 proto 文件中字段后面的编号,Length 是这个字段对应的值的字节长度,Value 就是具体的值了,最终将全部数据拼装成一个流,以下图:
由图咱们得知,ProtoBuffer 存储是紧密的,各个字段很是紧凑,不会浪费空间,若某个字段没有赋值,则不会出如今序列化后的数据中,相应字段在解码时才会被设置默认值
T 表明的 tag 是由 fieldNumber(字段编号)和 wireType(上图中最左边的 0,1,2...)组成的,fieldNumber 保证了字段不重复和他在数据流中的位置,wireType 标记了数据类型,若是是 varint 编码,fieldNumber 也保证了数据字节的长度 (L)
https://www.zhihu.com/search?...
https://zhuanlan.zhihu.com/p/...
https://learnku.com/articles/...