计算机网络
计算机网络
网络模型
OSI七层模型、TCP/IP模型、教学使用的五层模型
各层协议
应用层:DNS(port:53)、HTTP(80)、HTTPS(443)、SMTP、FTP(21)、SSH(22)
传输层:TCP(面向连接的,可靠的)、UDP(不可靠的,尽最大可能交付的)
网络层:IP
...
DNS(Domain Name System)
寻找域名与Ip之间的映射
浏览器缓存-本地DNS服务器-根域名服务器-顶级域名服务器-权威域名服务器
DNS的寻找域名和IP映射是基于UDP协议实现的,主要原因是为了更加的快速、高效、轻量,并且数据小于UDP包的大小可以实现;但是DNS的区域传输(也就是从一个主DNS服务器备份到一个次DNS服务器),这个时候传输的数据较大,并且需要严格保证顺序和可靠性,所以要用TCP。
HTTP
HTTP1.0:短链接
HTTP1.1:默认长连接(connect:keep-alive),流模式代替缓存模式,允许客户端发送多个请求(服务端还是要按照顺响应)
HTTP2.0:头部信息和数据体信息都是二进制,允许客户端发送多个信息(服务端可以不按顺序返回),报头压缩,服务端能够直接发消息
HTTP3:解决TCP带来的问题,使用UDP和QUIC(保证可靠传输,将TCP和TLS的六次握手合并成三次)
TCP
TCP三次握手
客户端发送建立请求SYN=1的报文(seq=x),由CLOSE状态进入SYN_SENT状态,此时服务端需从CLOSE状态更改为LISTEN状态接受请求报文,服务端接收到SYN报文后进入SYN_RECV状态,发送SYN=1、ACK=1的请求、确认报文(seq = y、 ack = x + 1),客户端收到该确认报文后,进入ESTABLISHED状态认为连接建立,同时因为也收到了SYN报文,所以还需要发一个ACK = 1的确认报文(seq = x + 1,ack = y + 1),服务端接收到该报文之后认为连接建立,也进入ESTABLISHED状态,至此一个TCP连接建立完成。
为什么不是两次或者三次?
如果是两次的话,客户端发送请求报文,服务端就会认为建立连接并发送确认报文,这个时候如果确认报文丢失,客户端发生超时重传,服务端就会建立多个连接浪费资源
四次的话没有必要,可以合并成三次来节约时间
TCP四次挥手
客户端发送FIN = 1 的连接关闭报文(seq = x),由ESTABLISHED状态进入FIN_WAIT1状态,服务端接收到该报文后,发送ACK = 1的确认报文(seq = y,ack = x + 1)同时进入CLOSED_WAIT状态,并开始处理未发送完的消息,客户端收到该确认报文后,进入FIN_WAIT2状态,服务端将剩余消息发送完之后,发送FIN = 1 的连接关闭报文(seq = w)并进入LAST_ACK状态等待最后客户端确认,(注意,如果服务端没有需要处理的消息,完全可以将ACK和FIN合并成一个报文实现三次挥手,此时客户端就不需要进入FIN_WAIT2状态了),客户端收到FIN报文后,发送ACK=1的确认报文(seq = x + 1,ack = w + 1),并进入TIME_WAIT状态(持续2MSL时间)(防止该确认报文丢失和旧消息传递出现问题),服务端收到该报文后进入CLOSED状态,连接关闭。
MSL:Maximum Segment Lifetime,是一个报文传输的最大生存时间
SYN Flood攻击
一种DDos攻击,攻击者发送多个连接建立的请求报文,服务端回应后,不发送最终请求报文,导致服务端半连接队列资源被占满。
防御方法:SYN Cookie半连接时生成cookie,只有收到带有该cookie的ack才建立连接和SYN防火墙使用防火墙代理,当收到ack时才建立连接。注意这两种措施都是补充,不能完全替代半连接队列
保活计时器
防止客户端都挂了,服务端不知道还在傻傻的等。当超过两个小时服务端没有收到消息时,服务端向客户端发一个心跳,如果没收到客户端回应,则每隔75秒再发送一次,如果十次都没响应,说明客户端挂了,服务端可以关闭连接了。
TCP可靠传输
- 面向连接的(三次握手)
- 校验和(确保发送的数据和接受的数据没有偏差)
- 序列号确认/应答
- 流量控制(滑动窗口)(发送端和接收端都有一个窗口并且会将窗口可用大小通过报文中的win进行传递)
- 最大消息长度
- 超时重传
- 拥塞控制(慢启动、拥塞避免、拥塞发生、快速恢复)
拥塞控制
慢启动:开始时cwnd指数级增长;拥塞避免:cwnd当达到sst时,线性增长;拥塞发生:当出现丢包时,认为拥塞已经发生,这个时候有两种情况,超时重传和快速重传。如果是超时重传,则sst会变为cwnd/2,cwnd会变为1,重新慢启动过程;如果是快速重传,则cwnd = cwnd/2,sst = cwnd,进入快速恢复算法。
Nagle算法和延迟确认
如果发送和确认报文携带的数据很少但是头信息很大,那么就会导致效率不高,Nagle算法和延迟重传就是解决这个问题
Nagle算法:当没有未被确认的消息,可以直接发消息;如果有未被确认的消息,则等到消息都被确认或者囤积的长度达到MSS时再发送
延迟确认:确认方发送的ACK报文只有确认没有数据所以性能较低。当有ACK报文需要传输时,不立刻传输,而是等有数据的响应报文传输时一起传输,如果等待期间发送方发来了数据也立刻传输
HTTP无状态和Session、Cookie
HTTP是无状态的,无法保存会话信息。
Cookie将信息存储在客户端,Session将信息存储在服务端
Cookie存储信息较短且不安全,Session存储信息长的多,且存在服务端较为安全
Session一般会将SessionId放在Cookie或者本地缓存(sessionStorage)中,将该信息传入后端之后,根据Session找到对应信息
Session有个问题,就是在分布式系统中,同一个SessionId在不同服务实例里面可能不一样或者不存在,这个时候可以使用Redis做缓存让服务端都能看到,或者直接改用JWT令牌,交由应用端解析处理
JWT令牌
现在大多项目都是使用JWT令牌来存储状态信息,这样的话就不像Session那样需要额外存储信息,而是通过一个token在后端程序中动态获取用户信息。
有一个问题就是JWT可能会发生泄漏,但是这个JWT你又无法收回。此时你可以立刻将该JWT失效(一般设置了失效时间),刷新JWT换用一个新的JWT,或者维护一个黑名单将这个JWT放到黑名单中,每次先校验一下是不是这个黑名单的。
JWT可以存在LocalStorage、SessionStorage或者Cookie中,前后端分离项目一般将JWT放在Authorization中,区别就是,Cookie是浏览器自动携带的,而Authorization是我们的前端代码通过JS手动加上的。
HTTPS
再建立TCP三次握手之后还通过SSL/TLS三次握手建立加密通信连接。
SSL/TLS三次握手:首先服务端通过CA获得证书并发送给客户端,客户端验证证书(CS Hash值),获得证书中的公钥,并且生成一个Key(后续用这个key和对称加密算法传输数据),使用公钥对这个key加密,并发送给服务端,服务端通过私钥解密,获得这个key,然后通过这个key和协商好的对称加密算法将数据进行加密并进行传输。
