面试全文
浏览器发出一个请求到收到响应经历的步骤
- 浏览器解析用户输入的URL,生成HTTP格式的请求
- 根据URL域名从本地hosts文件中查找是否有映射IP;如果没有,就将域名发送给电脑所配置的DNS进行域名解析,得到IP地址
- 浏览器通过操作系统将请求通过四层网络协议进行打包和发送,途中经过各种路由器、交换机,最终达到目标服务器
- 服务器收到请求后,根据端口,将请求传递给绑定了该端口的应用程序
- 收到请求数据后,按照应用层协议的格式进行解析,得到所要访问的请求
如果是tomcat服务器,按照http协议的格式进行解析,得到要访问的
servlet
,也就是对应的控制器
- 然后servlet来处理这个请求
如果是springMVC,通过
DispatchServlet
,找到对应的Controller中的方法,并执行该方法
- 将得到的响应结果封装为HTTP响应格式,并在此通过网络发给浏览器所在的服务器
- 浏览器所在的服务器得到结果后,传递给浏览器,浏览器负责解析并渲染
TCP网络分层
客户端发送HTTP数据包 | 服务端接受HTTP数据包 | |
---|---|---|
1. 根据HTTP协议组装数据包 | 应用层,HTTP协议 | 9. HTTP报文解析 |
2. 增加TCP头部,包含目标端口号、序列号等 | 传输层,TCP协议 | 8. TCP报文解析 |
3. 增加IP头部,包含源IP地址等 | 网络互联层,IP协议 | 7. IP报文解析,传送数据包、指定路由 |
4. 增加以太网头部,包含MAC地址等 | 网络访问层,硬件访问相关 | 6. 根据MAC地址,判断包是否发给该服务器 |
物理层 |
- 报文结构,层层解析 | 以太网头 | IP头 | TCP头 | GET / HTTP / 1.1 | | :---: | :---: | :---: | :---: |
- 应用层,负责内容,如果相互传递报文,如
HTTP
、HTTPS
- HTTP,负责传输内容,超文本传输协议,是一个基于请求与响应,无状态
(与事物处理没有记忆能力)
的,应用层的协议,不会对通信放进行确认,无法保证数据完整- HTTPS,基于HTTP协议,通过SSL或TLS提供加密处理数据、验证对方身份以及数据完整性保护
- 传输层,负责两台主机之间的
应用进程之间的端对端通信
,如TCP
、UDP
- 网络互联层,负责主机到主机之间的通信,以
IP地址
标识,进行访问 - 网络访问层,网络接口层,负责实际内容的传输,
以太网、WIFI、蓝牙
的工作层,主机到物理已经的链接协议 - 分层的好处
- 各层独立,限制了依赖关系的范围,各层都有标准化的接口,不需要知道其他层如何工作,可扩展性好
- 灵活性更好,路由不需要应用层和传输层,只需加载需要负责处理的协议即可
- 易于测试和维护,可以独立测试某一层
- 促进标准化,每一层职责清晰
TCP的三次握手为什么是三次,不是两次或者四次
- SYN,Synchronize Sequence Numbers,同步标志
- ACK,Acknowledgement Number,确认标志
- TCP面向连接的通信传输,整个过程需要发送
3个报文
,完成建立连接
- 客户端发送syn报文,设置序号x
- 服务端发送syn报文,设置序号y,ack报文,设置序号x+1
- 客户端发送ack报文,检查第二次收到的是否为ack为x+1,如果正确,回复ack=1
![]()
- 如果仅两次,无法确认客户端的接受完毕,服务端单方面建立连接,浪费连接资源
客户端,发送一个报文,此时报文滞留,通过两次握手,服务端单方面建立连接,等待客户端发送数据;但是此时,这个报文对于客户端是失效的,无视服务端的确认请求
- 三次足够确认双方的确认,没必要做四次
TCP的四次挥手,为什么是四次,不能是三次
- FIN,Final
- 终止TCP连接
- 服务端收到客户端断开连接的请求,只是进入
CLOSE_WAIT
状态,等待关闭,第二次和第三次之间,服务端需要释放一定的资源,存在一定的延迟;如果将第二次和第三次
合起来,要等服务端所有资源释放后,才会发送,那么客户端接收到连接关闭的ack时,要等待较长的时间,但是当客户端在一定时间内,没有立即收到关闭请求的响应,会进行重发,确保报文的可达性
为什么SYN/FIN不包含数据,却消耗一个序列号
- 凡是需要对端确认的,一定消耗TCP报文的序列号,SYN和FIN需要对端确认
- 保证数据的顺序和完整性,通过查看序列号和确认号可以确定数据传输是否乱序
半连接队列和SYN Flood攻击
- 半连接队列,服务端收到
第一次握手SYN报文
,相关信息放到半连接队列中,同时回复SYN+ACK
给客户端;当再次收到第三次握手ACK报文
,如果这时全连接队列没满,那么从半连接队列拿出相关信息放入到全连接队列中 - SYN Flood攻击,洪泛攻击,针对半连接队列的,攻击方不停地建连接,但是建连接的时候只做
第一步握手
,第二步握手
中攻击方收到服务端的SYN+ACK
后故意扔掉什么也不做 - 客户端大量伪造IP发送
第一次握手SYN报文
,服务端回复ACK+SYN
到一个未知的IP(大量无辜的服务器上),会造成服务端大量连接处于SYN_RCVD 半连接
状态,而服务器的半连接队列大小是有限的,如果半连接队列满了,无法响应正常请求
TCP快速打开TFO的原理
- TFO,TCP Fast Open,快速打开,是在TCP协议上的扩展协议,在发送
第一个SYN包
时就开始传输数据,要求当前客户端之前已经完成过正常的三次握手
- 两个阶段,请求
Fast Open Cookie
和真正开始TCP Fast Open
- Cookie,存储在用户本地的数据
- Fast Open Cookie,在第一次进行三次握手时,请求Cookie,并保存在本地
现在服务端不是立刻回复
SYN+ACK
,而是通过计算得到一个SYN Cookie
, 将这个Cookie放到 TCP 报文的Fast Open
选项中
- 真正开始
- 通过校验Cookie的合法性,检查是否可以直接建立连接,如果不合法,丢包,进行正常的三次握手
- 服务端的ACK,不用等到接收到HTTP响应后才发送,两者没有关系
- 优点
- 利用握手去除一个往返RTT
(Round-Trip Time,往返时延)
,表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延- 防止SYN Flood 洪泛攻击,需要携带cookie的请求
TCP报文中的时间戳有什么作用
- 在TCP头部信息的选项中
- TS value,发送方时间戳(发送时间),TS Echo Reply,回显时间戳(接收到数据时,得到的发送时间)
- 发送方在发送数据时将发送数据的时间
X
放到发送方时间戳TSval
中- 接收方在接收到数据的时候将收到的时间
X
原封不动的放到回显时间戳TSecr
中,同时将自己发送数据的时间Z
放到发送方时间戳TSval
中
- 计算往返时延RTT,如果发送请求时发送了重传,可以通过
TSval和TSecr
计算出时延
获得报文往返时间大量样本,从而的相对精确的估算连接中报文的往返时间
- 防止序列号回绕,序列号为32位,当超过
2^32位
时,就会溢出回绕,进行重置,在高速网络中,序列号在很短时间内会被重复利用
- 当大量数据传输时,中间某一个包滞留,等序列号被重复利用时,服务端才正常收到,而此时这个数据包,与其他数据包序号一致,数据紊乱
- 此时可以通过时间戳进行区分,直接丢弃掉与最近接收到的报文段时间戳相差最远的那个报文段,丢到序列号相同但是老的报文
TCP的超时重出时间是如何计算的
- 超时重出机制,间隔一段时间没有等到数据包的回复,重传这个数据包
- 重出间隔,超时重出时间,Retransmission TimeOut
- 经典方式,适用于RTT波动比较小的情况,其中RTT的值使用
平滑往返时间
进行计算
取平均值,第一次500ms,第二次800ms,第三次RTO取650ms
- 平滑往返时间,Smoothed round trip time,SRTT,经过平滑后的RTT的值,每一次测量RTT,就对SRTT作一次更新
- 平滑因子接近于1,接近于上一次SRTT的值,与新的RTT的值关系不大,表现的结果为
对短暂的时延变化不敏感
- 平滑因子接近于0,接近于新的RTT的值,表现的结果为
对时延变化更敏感,能更快速根据时延变化而变化
TCP流量控制
- TCP需要把发送的数据放到
发送缓存区
,将接收到的数据放到接收缓存区
- 流量控制,通过接收缓存区的大小,控制发送端的发送,如果接收缓存区满了,就不能继续发送
为了控制发送端的频率,接收端会告知发送端自己的
接收窗口rwnd
,接收缓存区中的空闲部分
- 在
ack确认报文
中,带有一个窗口大小,告诉发送端,下一次能接收的数据大小,接收端有多少是空闲的
- 通常TCP连接之初发送方都是由一个小的窗口开始,然后每次接收方在响应新的ACK时,发送方就会增大一些窗口大小
- 这个发送窗口就会持续增长直到达到窗口大小的最大限制。当接收方在一个往返时间内没有给发送方响应一个ACK,这个发送窗口大小将会被减少
- 窗口大小,为接收缓存区中的空闲部分
- 发送端数据包的状态
- 已发送且确认
- 已发送未确认
- 未发送,但是接收段可以接受(有空间接收)
- 未发送,且不可以发送(没空间接收)
- 发送端通过滑动窗口的形式,对数据包进行顺序发送
- 发送端速度比较慢,服务端有空间可以接受,此时窗口处于等待ack和有信息准备发送
- 发送端速度比较快,此时发送端的发送窗口中,全部等待ack
TCP的Keep-alive原理
- 一个TCP连接上,如果通信双方都不想对方发送消息,连接上就不会有任何数据交换
- 为了解决
客户端宕机,但是服务端不知道,只能等待的情况
- Keep-alive,检测长时间死连接的需求,
探测对端的连接有没有失效
- 定时发送探测包来探测连接的对端是否存活
- 默认情况下7200s没有数据包交互才会发送
keepalive
探测包,常用组件没有开启Keep-alive
特性,在应用层做心跳机制
- HTTP协议的Keep-Alive,意图在于短时间内连接复用,希望可以短时间内在同一个连接上进行多次请求/响应
TCP中的端口号
- 源端口,发送端的端口(可以是临时建立的端口号)
- 目标端口,接收端端口
- 两个字节正数表示,16位二进制,一共65536个端口
- 熟知端口号 0~1023
- HTTP 80
- HTTPS 443
- SSH 22
- 已登记端口号 1024~49151
- MySql 3306
- Redis 6379
- MongoDB 27017
- 临时端口号 49152~65535
TCP场景问题一
- 当AB两个主机建立了一个TCP连接,A发给B两个连续的TCP端,大小分别为300和500,第一个报文序号200,B接收到两个报文后,返回的确认号是多少
- 答,返回
200+300+500 = 1000
- 第一个报文段序是200,第一个TCP段为300字节,所以
第一段的结束为499
,同时第二段的开始也是499,长度为500,最后的结束为999,故确认号为999+1=1000,为结束的序列号+1
TCP场景问题二
- 收到IP数据包解析后,怎么知道这个分组应该投递到上层的哪个协议(TCP/UDP)
- IP报文头中有
协议
,标明上层协议是哪个
Linux中
cat /ect/protocols
,ICMP为1,TCP为6,UDP为17![]()
TCP场景问题三
- TCP提供了一种字节流服务,而
收发双方都不保持记录的边界
,应用程序如何提供他们自己的记录标识 - 应用程序使用自己的约定来表示消息边界
Redis的
RESP protocol
使用回车+换行\r\n
telnet
- 检查远端端口是否打开,连接是否可达
telnet www.baidu.com 80
- 模拟发送http请求
GET / HTTP/1.1
Host: www.baidu.com
netstat
- 显示各种网络相关信息
netstat -at
所有tcp相关的网络连接
tcpdump
- 抓包,命令行流量分析工具
tcpdump -i any
指定对所有网卡进行抓包- 时间戳
tcpdump -i any host www.baidu.com
查看跟百度的交互情况curl www.baidu.com
访问
wireshark
- 下载链接
- 监听端口
host www.baidu.com
- 模拟访问
curl www.baidu.com
- 查看网络分层结构
网络结构层、互联层、传输层、应用层
TCP和UDP的区别
- TCP,Transfer Control Protocol
- UDP,User Datagram Protocol
- TCP 面向连接,可靠的,基于字节流的传输层协议,效率比较低,占用的系统资源比较多
- UDP,面向无连接的、不可靠的传输层协议,广播发送,有可能丢失消息,效率比较高,协议简单,占用系统资源比较少
类似广播,发送发,不管接收方,直接发消息
- 面向连接,指客户端和服务端的连接,双方在通信前,TCP需要三次握手建立连接,UDP没有建立连接的过程
- 可靠性,TCP保证连接的可靠
- TCP有状态,TCP会精确记录哪些数据发送了,哪些被对方接受了,哪些没有被接收到,保证数据包按序达到
- TCP可控制,当意识到丢包或者网络环境不佳,TCP会根据具体情况调整行为,控制自己的发送速度或者重发
设计QQ的网络协议
- 登陆采用
TCP协议和HTTP协议
,保证安全可靠,TCP发送信息,HTTP保存信息,登录之后,用一个TCP连接保持在线状态 - 好友之间发送消息,采用
UDP协议
,保证效率;通过服务器转发,通过上层协议保证消息完整,如果发送失败,提示客户端,进行重新发送
- 基于UDP的应用层协议:DNS 53 Domain Name Service (域名服务)
- TFTP 69 Trivial File Transfer Protocol(简单文件传输协议)
- SNMP 161 Simple Network Management Protocol(简单网络管理协议)
- NTP 123:Network Time Protocol (网络时间协议)
- 内网传文件采用
P2P技术
,内网中不需要服务器中转,纯P2P
- peer-to-peer,点对点技术
- P2P传输是去中心化的,每位用户每个节点既可以从其他节点得到服务,又充当节点向其他用户提供服务
- 纯P2P,节点同时作为客户端和服务器端,没有中心服务器和中心路由器
- 杂P2P有一个中心服务器保存节点的信息并对请求这些信息的要求做出响应。节点负责发布这些信息,中心服务器并不保存文件,让中心服务器知道它们想共享什么文件,让需要它的节点下载其可共享的资源
Cookie和Session的区别
- session存储在服务器端,比较安全;cookie在客户端
- session没有数据大小限制,cookie有
- 当服务器(Tomcat)第一次接收到客户端的请求,会开辟一块独立的
session
空间,建立一个session
对象,同时生成一个session id
,通过响应头的方式保存在客户端浏览器的cookie
中,以后客户端的每次请求,都会在请求头部带上这个session id
,这样就可以对应上服务端上的一些会话信息,比如用户的登录状态 - 当服务端从单体应用升级为分布式之后,需要如何扩展
Cookie和Session
- 多个tomcat形成服务器集群,客户端每次访问的服务器都不同,需要保证
session id
共享- session黏贴,在负载均衡(IP轮询)中,保证客户端所有请求只会访问(转发)同一个服务器(tomcat实例);当这个服务器出现问题之后,请求就会被转发到其他实例上,导致用户信息丢失
- session复制,当一个服务器上保存了session信息后,主动将session复制到其他服务器;在复制过程中,访问仍在继续,容易产生session,导致session混乱、浪费
- session共享,将服务端的session信息,保存在第三方中(redis)
- 如果一个服务器集群,跑不同的应用,而保存客户端的一个session,实现单点登录,登陆一个应用,就可以登录多个应用,
淘宝、支付宝、天猫
如果没有Cookie,Session还能进行身份验证吗
- 如果没有客户端的Cookie,Session无法进行身份验证,找不到
JSESSIONID
HTTP和HTTPS的区别
- HTTP,应用最为广泛的网络通信协议,基于TCP协议,不同浏览器访问不同服务器上的服务,工作更为高效,减少网络传输
- HTTPS,基于HTTP协议,HTTP+SSL,通过SSL(Secure Socket Layer)或TLS提供加密处理数据、验证对方身份以及数据完整性保护,是目前最为安全的解决方案
- 有状态,服务不好扩展,需要将状态进行同步共享
- 区别
- HTTP连接简单、无状态(与事物处理没有记忆能力);HTTPS,是有状态的,数据传输经过证书加密,安全性更高
- HTTP免费,HTTPS需要申请证书,而证书是收费的
- 传输协议不同,端口不同,HTTP默认80,HTTPS默认443
- HTTPS的缺点
- HTTPS的握手协议比较费时,在三次握手的基础上,增加了证书的确认过程,会影响服务的响应速度以及吞吐量
- 并不是安全的,证书体系并不是完全安全的,面对DDOS(分布式拒绝服务攻击 Distributed denial of service attack,伪装大量客户端进行错误访问)的攻击时,几乎不起任何作用,
- 功能越强大的证书,费用越高
HTTPS是如何保证安全传输的
- https通过对称加密、非对称加密、数字证书等方式
- 客户端向服务端发送数据之前,要先建立TCP连接,建立完成后,服务端对客户端发送加密相关的信息
- 对称加密,客户端用一个密钥加密,服务端用同一个密钥解密,在发送数据时,服务端会将密钥提前发给客户端,会被劫持
- 非对称加密,服务端用私钥,客户端用公钥,服务端会通过中间人把公钥发送给客户端,而中间人过程中可以自己伪造一个私钥,将伪造的私钥对应的公钥发送给客户端;中间人再用服务端的公钥加密后,给服务端
- 数字证书,服务端从CA申请证书(私钥),服务端将私钥生成的数字证书发送给客户端,浏览器通过
内嵌的CA获取的公钥
和服务端的私钥进行数据加密;中间人就无法伪造CA发布的公钥
- 数据证书中,服务端向客户端发送公钥时,将公钥和服务端相关信息通过Hash算法生成消息摘要,再通过数据证书提供的私钥对消息摘要进行加密生成
数字签名
,再把没进行Hash算法之前的信息和数字签名整合形成最终的数字证书,把数字证书发送给客户端;客户端收到数字证书后,用其中的公钥来解密数字证书,得到非对称加密要用的公钥
- 就算中间人进行拦截,揭秘出非对成加密的公钥,但是无法伪造数字证书,客户端的数字证书是通过浏览器内嵌的CA进行申请的,不容易被伪造
- 某个网站需要支持https,是需要申请数字证书的私钥的,而生成能被客户端解析的数字证书,也需要申请私钥