TCP 层发送每一个报文的时候,都需要加上自己的地址(即源地址)和它想要去的地方(即目标地址),将这两个信息放到 IP 头里面,交给 IP 层进行传输。
IP 层需要查看目标地址和自己是否是在同一个局域网。如果是,就发送 ARP 协议来请求这个目标地址对应的 MAC 地址,然后将源 MAC 和目标 MAC 放入 MAC 头,发送出去即可;如果不在同一个局域网,就需要发送到网关,还要需要发送 ARP 协议,来获取网关的 MAC 地址,然后将源 MAC 和网关 MAC 放入 MAC 头,发送出去。
网关收到包发现 MAC 符合,取出目标 IP 地址,根据路由协议找到下一跳的路由器,获取下一跳路由器的 MAC 地址,将包发给下一跳路由器。
这样路由器一跳一跳终于到达目标的局域网。这个时候,最后一跳的路由器能够发现,目标地址就在自己的某一个出口的局域网上。于是,在这个局域网上发送 ARP,获得这个目标地址的 MAC 地址,将包发出去。
目标的机器发现 MAC 地址符合,就将包收起来;发现 IP 地址符合,根据 IP 头中协议项,知道自己上一层是 TCP 协议,于是解析 TCP 的头,里面有序列号,需要看一看这个序列包是不是我要的,如果是就放入缓存中然后返回一个 ACK,如果不是就丢弃。
应用层的队首阻塞(HTTP/1.1-based head of line blocking): HTTP/1.1可以使用多个TCP连接,但对连接数依然有限制,一次请求要等到连接中其他请求完成后才能开始(Pipeline机制也没能解决好这个问题),所以没有空闲连接的时候请求被阻塞,这是应用层的阻塞。 HTTP/2底层使用了一个TCP连接,上层虚拟了stream,HTTP请求跟stream打交道,无需等待前面的请求完成,这确实解决了应用层的队首阻塞问题。
传输层的队首阻塞(TCP-based head of line blocking): 正如文中所述,TCP的应答是严格有序的,如果前面的包没到,即使后面的到了也不能应答,这样可能会导致后面的包被重传,窗口被“阻塞”在队首,这就是传输层的队首阻塞。 不管是HTTP/1.1还是HTTP/2,在传输层都是基于TCP,那么TCP层的队首阻塞问题都是存在的(只能由HTTP/3(based on QUIC)来解决了),另外,HTTP/2用了单个TCP连接,那么在丢包率严重的场景,表现可能比HTTP/1.1更差。