终极解密输入网址按回车到底发生了什么
详解输入网址点击回车,后台到底发生了什么。透析 HTTP 协议与 TCP 连接之间的千丝万缕的关系。掌握为何是三次握手四次挥手?time_wait 存在的意义是什么?全面图解重点问题,再也不用担心面试问这个问题。
大致流程
URL 解析,解析 http 协议、端口、资源地址。
DNS 查询:首先查询本地 host,再访问 DNS 服务器将 域名解析成 ip 地址。
建立 TCP 连接。
服务器收到请求后处理,并且构造响应返回给客户端。
客户端接收 HTTP 报文响应。
渲染页面,最后有可能会四次挥手断开连接,也可能不会而是复用连接。
重点来了:
如何理解 TCP 的三次握手与四次挥手?每次握手客户端与服务端是怎样的状态?
为何挥手会出现 2MSL,遇到大量 Socket 处在 TIME_WAIT 或者 CLOSE_WAIT 状态是什么问题?
三次握手与四次挥手的过程是怎样的?
HTTP 的报文格式又是怎样的?
URL 解析
url 遵守的规则是这个样子
scheme://host.domain:port/path/filename
每个名词的含义如下解释:
scheme 定义应用层协议类型,比如 http、https、 ftp 等;
host 定义域主机(http 的默认主机是 www);
domain 定义因特网域名,比如 segmentfault.com;
port 主机的端口,http 默认是 80, https 默认是 443;
path 服务器上的资源路径;
filename - 定义文档/资源的名称;
DNS 查询
浏览器不能直接通过域名找到服务器,只能通过 IP 地址。
那浏览器是如何通过域名查询到我们输入的 url 对应的 IP 呢?
浏览器缓存:按照一定频率缓存 DNS 数据。
操作系统缓存:如果浏览器缓存好啊不到记录则去操作系统中找。
路由缓存:路由器 DNS 缓存。
ISP 的 DNS 服务器:ISP 是互联网服务提供商(Internet Service Provider)的简称,ISP 有专门的 DNS 服务器应对 DNS 查询请求。
根服务器:ISP 的 DNS 服务器还找不到的话,它就会向根服务器发出请求,进行递归查询(DNS 服务器先问根域名服务器.com 域名服务器的 IP 地址,然后再问 .baidu 域名服务器,依次类推)
TCP 连接建立与断开
通过域名解析出 IP 地址以后就要建立 TCP/IP 连接了。
TCP/IP 分为四层,每一层都会加上一个头部再发送给下一层。到了接收方后,对应的每一层则把对应层的头部解析拆除,丢上上一层,跟发送端的过程反过来。
应用层:发送 HTTP 请求
浏览器从地址栏得到服务器 IP,接着构造一个 HTTP 报文,其中包括:
请求行包含请求方法、URL、协议版本 请求报头(Request Header):由 “关键字: 值”对组成,每行一对,关键字与值使用英文 “:” 分割 请求体:请求参数,并不是所有的请求有又请求参数。一般 get 参数 的格式 name=tom&password=1234&realName=tomson
,也可以将参数放在 body 里面。
传输层:TCP 传输报文
网络层:IP 协议查询 MAC 地址
链路层:以太网协议
标头:数据包的发送者、接受者、数据类型 数据:数据包具体内容
Mac 地址
三次握手
四次挥手
其实是客户端在发送 [FIN] 报文的时候顺带发了一个 [ACK] 确认上次传输确认。 接着服务端通过 80 端口响应了 [ACK] ,然后立马响应 [FIN, ACK] 表示数据传输完了,可以关闭连接。 最后浏览器通过 13743 端口 发送 [ACK] 包给服务端,客服端与服务端连接就关闭了。
SYN_SENT - 客户端发起第 1 次握手后,连接状态为 SYN_SENT ,等待服务端内核进行应答,如果服务端来不及处理(例如服务端的 backlog 队列已满)就可以看到这种状态的连接。 ESTABLISHED - 表示连接处于正常状态,可以进行数据传送。客户端收到服务器回复的 SYN+ACK 后,对服务端的 SYN 单独回复(第 3 次握手),连接建立完成,进入 ESTABLISHED 状态。服务端程序收到第 3 次握手包后,也进入 ESTABLISHED 状态。 FIN_WAIT_1 - 客户端发送了关闭连接的 FIN 报文后,等待服务端回复 ACK 确认。 FIN_WAIT_2 - 表示我方已关闭连接,正在等待服务端关闭。客户端发了关闭连接的 FIN 报文后,服务器发回 ACK 应答,但是没进行关闭,就会处于这种状态。 TIME_WAIT - 双方都正常关闭连接后,客户端会维持 TIME_WAIT 一段时间,以确保最后一个 ACK 能成功发送到服务器端。停留时长为 2 倍的 MSL (报文最大生存时间),Linux 下大约是 60 秒。所以在一个频繁建立短连接的服务器上通常可以看到成千上万的 TIME_WAIT 连接。
LISTEN - 表示当前程序正在监听某个端口时。 SYN_RCVD - 服务端收到第 1 次握手后,进入 SYN_RCVD 状态,并回复一个 SYN+ACK(第 2 次握手),再等待对方确认。 ESTABLISHED - 表示连接处于正常状态,可以进行数据传送。完成 TCP3 次握手后,连接建立完成,进入 ESTABLISHED 状态。 CLOSE_WAIT - 表示客户端已经关闭连接,但是本地还没关闭,正在等待本地关闭。有时客户端程序已经退出了,但服务端程序由于异常或 BUG 没有调用 close()函数对连接进行关闭,那在服务器这个连接就会一直处于 CLOSE_WAIT 状态,而在客户机已经不存在这个连接了。 LAST_ACK - 表示正在等待客户端对服务端的关闭请求进行最终确认。
可靠地实现 TCP 全双工连接的终止 在进行关闭连接四路握手协议时,最后的 ACK 是由主动关闭端发出的,如果这个最终的 ACK 丢失,服务器将重发最终的 FIN,因此客户端必须维护状态信息允 许它重发最终的 ACK。如 果不维持这个状态信息,那么客户端将响应 RST 分节,服务器将此分节解释成一个错误( 在 java 中会抛出 connection reset 的 SocketException)。因而,要实现 TCP 全双工连接的正常终 止,必须处理终止序列四个分节中任何一个分节的丢失情况,主动关闭 的客户端必须维持状 态信息进入 TIME_WAIT 状态。 允许老的重复分节在网络中消逝 TCP 分节可能由于路由器异常而“迷途”,在迷途期间,TCP 发送端可能因确认超时而重发这个 分节,迷途的分节在路由器修复后也会被送到最终目的地,这个 原来的迷途分节就称为 lost duplicate。在关闭一个 TCP 连接后,马上又重新建立起一个相同的 IP 地址和端口之间的 TCP 连接,后一个连接被称为前一个连接的化身 ( incarnation),那么有可能出现这种情况,前一 个连接的迷途重复分组在前一个连接终止后出现,从而被误解成从属于新的化身。为了避免 这个情 况,TCP 不允许处于 TIME_WAIT 状态的连接启动一个新的化身,因为 TIME_WAIT 状 态持续 2MSL,就可以保证当成功建立一个 TCP 连接的时 候,来自连接先前化身的重复分组已 经在网络中消逝。
保证 TCP 协议的全双工连接能够可靠关闭; 保证这次连接的重复数据段从网络中消失,防止端口被重用时可能产生数据混淆;
服务器处理请求并响应 HTTP 报文
起始行(Start Line):描述请求或者响应的基本信息。 Header:使用 key-value 的形式详细说明报文信息。 空行。 消息正文(Entity):传输的数据,图片、视频、文本等都可以。
GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT
。GET / HTTP/1.1
翻译成文字大概就是:“hello,服务器,我要请求根目录下的默认文件使用的是 HTTP 1.1 协议版本”。header 字段不区分大小写,通常是首字母大写; 字段名不允许有空格,可以使用 “-”,不能使用 “_”; 字段名必须紧接着 “:”,不能有空格,但是 “:” 后面可以有空格。 字段名顺序没有意义;
浏览器接收响应并渲染数据
根据 HTML 解析 DOM 树; 根据 CSS 解析出 CSS 规则树; 结合 DOM 树与 CSS 规则树,生成渲染树; 根据生成的渲染树计算每个节点的信息; 根据节点信息绘制画面展示给用户。