系列文章目录
常规后端面试准备
计算机网络常见问题:TCP & UDP,HTTP & HTTPS等
OSI 7层,TCP/IP 5层协议
- 物理层 — 如何传输一个bit(e.g. FDM,TDM)
- 数据链路层 — 如何正确传输一组bit,功能:framing,纠错等,MAC地址
- 网络层 — 如何将一个包从源地址发送到目的地址,IP地址
- 运输层 — 提供可靠/稳定的网络传输(抽象下层的所有网络细节),TCP/UDP
- 应用层 — 利用传输层提供的网络连接,实现不同应用,如:HTTP,FTP,SMTP…
TCP/UDP
TCP/UDP的区别与联系
- TCP vs UDP
- 基于连接 vs 无连接
- 资源较多 vs 资源较少(轻量)
- 结构复杂 vs 结构简单 — header 20字节(还有optional字段,总共最长60字节) vs 8字节
- 流模式(Byte Stream) vs 数据报模式
- 可靠传输 vs 不保证送达
- 保证顺序接收(seq) vs 不保证
- 拥塞控制 vs 无
- 保活 vs 无
- 如果已经建立了TCP连接但是客户端突然发生了故障(不接受数据,无法回复),TCP有一个保活计时器,服务器每收到一次客户端的请求都会重置改计时器,若规定时间内没收到客户端的任何消息,服务器会发送探测报文,一连发送10个都无反应的话,主动关闭连接
TCP/UDP各自的应用场景
- TCP
- HTTP,FTP,SMTP,POP3,TELNET
- 发消息,发邮件,文件传输(数据量不大,且需要保证不丢失)
- UDP
- DNS — 就是要快
- 视频聊天/直播,即使丢失几个画面影响也不大,同时数据量大需要速度,减小overhead
TCP如何做到可靠传输
- ACK + SEQ
- 检验和
- 超时重传
- 窗口控制
- 连接管理
TCP/UDP头部多大,含有什么字段
- TCP 头部最少20字节(无optional),最多60字节(含optional)
- 源,目的端口,各2字节
- 序列号,确认号,各4字节
- …
- 检验和,2字节
- UDP头部8字节(源,目的端口,长度,检验和各2字节)
TCP三次握手,四次挥手
- 握手
- —> SYN
- <— SYN ACK
- —> ACK
- 挥手
- —> FIN, ACK
- <— ACK
- <— FIN
- —> ACK
为什么需要三次握手
- 为什么3不是2:为了防止服务器端收到已失效的连接请求报文,造成错误;如有一个连接请求由于网络拥塞很久才到达(此时客户端已经和服务器端建立了TCP连接),服务器收到该请求后,假如返回ACK+SYN并立刻建立连接,那就会白白浪费资源,因为此时客户端根本不会使用该条连接。
- 为什么3不是4:提高效率,服务器返回的SYN和ACK可以放到一个包里面
为什么需要四次挥手
因为client端主动断开连接的时候,服务器端可能还有部分数据没有发送完毕,所以ACK和FIN不能一起发送。
为什么连接时候是三次,但是断开的时候是四次
因为连接的时候,服务器可以把SYN和ACK一起发送回去,ACK用于应答,SYN用于同步;但是关闭连接时,服务器只能先发ACK表示收到FIN消息,但是要等所有数据都发送完毕之后,才能发送FIN。
TCP半连接 (SYN攻击)
在三次握手过程中,服务器发送SYN-ACK之后,收到客户端的ACK之前的TCP连接称为半连接(half-open connect,此时处于SYN_RECV状态);服务器会维护一个半连接队列,存放所有当前的半连接,当收到客户端的ACK之后,会将对应的条目取出放入全连接队列中。注:服务器会定期重传SYN-ACK包,当重传次数超过系统设置最大次数,则丢弃该条目;
SYN攻击与DOS攻击很类似,利用了TCP的特性,短时间内发送大量“半连接请求”(故意丢弃服务端发回来的ACK-SYN),使得服务器的半连接队列满,从而无法接受新的连接。netstat -n -p TCP | grep SYN_RECV
若发现大量连接处于SYN_RECV状态,大概率是SYN攻击。
TIME_WAIT
有什么作用?为什么是2MSL(Maximum Segment Lifetime)?MSL一般是多长时间
因为client发送完最后的ACK之后,服务器可能会没收到,那么就会重复发送FIN给client,所以client需要等待一段时间,2MSL是为了一个发送(服务器发送FIN)和一个回复(客户端回复ACK)所需的最大时间。 注:MSL一般实现为30秒,RFC建议2分钟。
TIME_WAIT只出现在主动关闭连接方,大部分情况都是客户端主动关闭,但是也有服务器端主动关闭,如:一个简易的HTTP服务器,客户端发送HTTP请求后,服务器返回RESPONSE之后立刻主动关闭连接。
服务器端TIME_WAIT过多的原因:
- 网络拥塞,不断重发最后一个ACK(TIME_WAIT过程中,这条连接无法被复用)
- 短时间内高并发的短连接 (如1秒内100万条TCP连接,并且每次连接只持续10秒)
CLOSE_WAIT
服务端在收到客户端发来的FIN请求,返回一个ACK后就会进入CLOSE_WAIT状态,此时服务器在等待上层应用调用close()
方法断开连接,假如此时上层应用出现异常退出,没有close,就会卡死在这里。
CLOSE_WAIT过多的原因:上层程序设计有问题,没能调用close()
函数
TCP拥塞控制
- 慢开始,拥塞避免(cwnd拥塞窗口,ssthresh慢开始门限)
- cwnd < ssthresh,慢开始算法 — 每次RTT往返,cwnd加倍
- cwnd > ssthresh,拥塞避免算法 — 每次RTT往返,cwnd加1
- 如果RTT内没收到回复,ssthresh设置为当前窗口的一半并把cwnd设为1,重新开始
- 快重传,快恢复
- 快重传:接收端一旦收到失序报文,立刻发送重复确认,发送端若连续收到三个重复确认则立刻重传(不等超时)
- 快恢复:接收端收到三个重复确认之后,将sshthresh设置为当前窗口一半并将cwnd设置为ssthresh的值
- 优化框架:Google提出的BBR算法,腾讯的TCPA
TCP 粘包
由于数据量较小,发送端将多个TCP包合并成一个后发送 / 接收端长时间未接收,多个包到达缓冲区被合并成一个。因为TCP是基于流传输的,所以会出现这样的情况(UDP是基于数据报的,所以不会出现这种情况)。解决方法是可以自己在待传输的数据里面增加一个数据长度之类的(e.g. HTTP POST data的chunk模式,每个chunk前面会有数据的长度),或者使用特殊的分界符(e.g. HTTP头部\n\n
分界)。
Socket编程
Select 和 Epoll
- 都属于NIO(Non-blocking IO)
- Select是监听多个fd,任意一个准备好后通知程序,程序遍历所有fd处理,
O(n)
- Epoll底层用红黑树进行优化,同时通过回调函数的形式,通知程序进行处理,
O(1)
(回调函数直接处理事件)
connect()
- 指定对向地址和端口号
- TCP中调用
connect()
方法,底层经历三次握手 - UDP中调用
connect()
方法,只是记录目标地址和端口,不会有任何其他操作 - 对比:TCP调用几千次
connect()
会造成几千个连接,反之UDP只会保存最后一次的地址和端口号(不断覆盖)
HTTP
HTTP有哪些请求方式
- 最最最常规:GET & POST
- 一个是只读 (建议,当然也可以写),一个是可写
- 参数在URL里面还是在body里面
- HEAD,DELETE,PUT,CONNECT(模仿HTTPS),OPTIONS,PATCH,TRACE
从浏览器输入一个网址开始到看到网页,中间发生了什么
- URL解析
- 首先判断浏览器有无本地缓存,缓存是否过期,是否需要重新验证
- 从而判断是否需要发起网络请求,需要的话继续下一步
- DNS查询(域名 — IP 映射)
- 查询顺序
- 查询方法(递归 + 迭代)
- 建立TCP连接
- 三次握手 & 四次挥手
- 半连接
- TIME_WAIT,CLOSE_WAIT
- 发送HTTP请求报文(request)
- 请求报文结构
- 请求方式(GET,POST…)
- 服务器处理请求
- 浏览器接收响应(response)
- 响应报文结构?
- 浏览器渲染页面(HTML,CSS,JavaScript…)
DNS域名解析的顺序/原理
- core:递归+迭代
- 递归:一路找下去,没有结果不返回
- 迭代:多次查找(多次返回结果)
- 查询顺序:
- 浏览器缓存 —> 本机缓存(localhost)—> 路由器 —> 本地DNS (递归)
- 本地DNS —> 根域名(迭代)
- 首先查根域名,根域名不知道,去.com域名服务器查,逐级往下
如何定位资源,URL V.S. URI
- URL:Universal Resource Locator
- URI:Universal Resource Identifier
区别在于一个是Locator一个是Identifier,URL是URI的子集,URI是一种编号,可以定位区分某个资源的一种独一无二的编号,如身份证号;URL是一个位置/地址,一个可以定位某一具体资源的独一无二的地址,如住址详细到房间号
HTTP请求(request)/回应(response)的组成
request
第一行结构:请求方法(GET, POST...)URL HTTP协议版本号
紧接着:Header(键值对的形式定义各种参数,如Host)
optional:body(针对POST请求,还会有body包含所有信息)
GET /~bmr23/ece568/class.html HTTP/1.1
Host: people.duke.edu
response
第一行结构:HTTP协议版本号 响应代码 响应内容
(代码和内容一般一一对应,如200 OK
, 404 Not Found
)
紧接着:Header(键值对的形式定义各种参数,如Date,body数据长度)
optional:body,假如是请求文件,返回的文件内容会在body里面
HTTP/1.1 200 OK
Date: Wed, 25 Mar 2020 00:29:28 GMT
Server: Apache
HTTP长短连接的联系与区别,现在用哪种比较多
- 短连接:client和server每进行一次HTTP操作,就建立一次连接,任务结束就中断连接(只有一次数据往返)
- 长连接:打开网页后,连接不会关闭(TCP连接),若再次访问该server上的资源,会继续使用已有连接
- 需指定:
Connection: keep-alive
- 拓展,TCP长连接,保活,心跳检测
- 需指定:
- HTTP 1.0默认使用短连接,HTTP 1.1默认使用长连接
- 长连接的好处,HTTP长连接其实本质上是TCP长连接,这样访问一个网页可以用同一个TC连接发送接收多个HTTP请求,如:请求一个网站,可能会需要得到html,css,JavaScript,图片等多个文件(分别是不同的HTTP请求),使用长连接的话就可以复用同一个TCP连接,overhead较小
HTTP vs HTTPs
一句话概括,HTTP明文传输报文不够安全,故HTTPs会加密报文后再进行传输。具体加密流程:
- 对称加密 vs 非对称加密
- 对称加密:双方使用同一个密钥进行加解密,问题:如果这个密钥被攻击者得知了,就没用了
- 非对称加密:公钥和私钥,客户端保存私钥,发送公钥给服务端
- 能否只使用非对称加密?
- 不行,因为这个只能保证一个方向的安全传输(服务器到客户端,因为私钥只有客户端知道),假设公钥被攻击者得到了,那么所有客户端发过来的数据,攻击者都可以解密
- 那能否使用两套公钥密钥从而保证双向安全?
- 可以,但是开销太大,非对称加密的运算开销远大于对称加密(一般来说对称加密都是位运算,很快;但是非对称加密可能涉及取模,大数乘法之类的)
- 对称加密 + 非对称加密
- 可以,HTTPs就是采用的这种方案。服务器生成公钥(K)和私钥(K’),将公钥传输给客户端,客户端拿到K之后,生成一个自己的密钥X(用于对称加密),然后用K加密后将X传输给服务器,最后所有信息都用X来进行对称加密
- 最后一个问题,中间人攻击(替换掉了K)
- CA,数字证书,可信的第三方机构颁发证书给服务器,客户端会验证证书的有效性(数字签名)
- CA:拥有非对称加密的私钥和公钥。
- CA对证书明文信息进行hash。
- 对hash后的值用私钥加密,得到数字签名。
- 客户端:拿到证书,得到明文T,数字签名S。
- 用CA机构的公钥对S解密(由于是浏览器信任的机构,所以浏览器保有它的公钥),得到S’。
- 用证书里说明的hash算法对明文T进行hash得到T’。
- 比较S’是否等于T’,等于则表明证书可信
- 攻击者若修改了证书明文部分,由于没有私钥,不可能修改签名部分
- CA,数字证书,可信的第三方机构颁发证书给服务器,客户端会验证证书的有效性(数字签名)