简要介绍网络模型以及常用协议

七层OSI模型

  • 应用层:HTTP、HTTPS、FTP、Telnet、SSH、SMTP、POP3等。
  • 表示层
  • 会话层
  • 传输层: 传输控制协议(TCP/UDP)
  • 网络层: 互联网协议(IP)
  • 数据链路层: 逻辑链路控制(logical link control,LLC)子层和介质访问控制(Media access control,MAC)子层
  • 物理层

关键词: TCP/IP的四层模型

HTTP/1

定义: HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范

请求大致流程图:

HTTP1.0

  1. 增加了 HEAD、POST 等新方法;

  2. 增加了响应状态码,标记可能的错误原因;

  3. 引入了协议版本号概念;

  4. 引入了 HTTP Header(头部)的概念,让 HTTP 处理请求和响应更加灵活;

  5. 传输的数据不再仅限于文本。

关键词: 短链接,队首阻塞,多TCP链接

HTTP1.1

  1. 增加了 PUT、DELETE 等新的方法;

  2. 增加了缓存管理和控制;

  3. 明确了连接管理,允许持久连接;

  4. 允许响应数据分块(chunked),利于传输大文件;

  5. 强制要求 Host 头,让互联网主机托管成为可能。

关键词: 长链接(connection:Keep-alive),可复用TCP链接(FIFO)

HTTP2

基于 Google 的 SPDY 协议,HTTP/2 虽然使用 “帧 ”“流” “多路复用”,没有了“队头阻塞”,但这些手段都是在应用层里,而在下层协议中,也就是 TCP 协议里,还是会发生 “队头阻塞”。

  1. 二进制协议,不再是纯文本;

  2. 可发起多个请求,废弃了 1.1 里的管道;

  3. 使用专用算法压缩头部,减少数据传输量;

  4. 允许服务器主动向客户端推送数据;

  5. 增强了安全性,“事实上”要求加密通信。

  6. TLS 协议提供“ALPN(应用层协议协商)”扩展,让客户端和服务器协商使用的应用层协议,“发现”HTTP/2 服务。

特点

单个TCP链接(请求并行处理)

Stream多路复用,而不是有序和阻塞

二进制消息帧:二进制协议,头信息和数据包都是二进制,统称为帧,其中定义了10种不同类型的帧。

头部压缩:HPACK

服务端PUSH: 主动推送消息给客户端缓存

二进制协议格式

帧开头是 3 个字节的长度(但不包括头的 9 个字节),默认上限是 2^14,最大是 2^24,也就是说 HTTP/2 的帧通常不超过 16K,最大是 16M。

长度后面的一个字节是帧类型,大致可以分成数据帧控制帧两类,HEADERS 帧和 DATA 帧属于数据帧,存放的是 HTTP 报文,而 SETTINGS、PING、PRIORITY 等则是用来管理流的控制帧。

第 5 个字节是非常重要的帧标志信息,可以保存 8 个标志位,携带简单的控制信息。

常用的标志位有:

END_HEADERS表示头数据结束,相当于 HTTP/1 里头后的空行(“\r\n”),

END_STREAM表示单方向数据发送结束(即 EOS,End of Stream),相当于 HTTP/1 里 Chunked 分块结束标志(“0\r\n\r\n”)。

报文头里最后 4 个字节是流标识符,也就是帧所属的“流”,接收方使用它就可以从乱序的帧里识别出具有相同流 ID 的帧序列,按顺序组装起来就实现了虚拟的“流”。 虽然帧是乱序收发的,但只要它们都拥有相同的流 ID,就都属于一个流,而且在这个流里帧不是无序的,而是有着严格的先后顺序

扩展:10种帧的定义与其用途

DATA帧:

HEADERS帧:

PRIORITY帧:

RST_STREAM帧:

SETTING帧:

PUSH_PROMISE帧:

PING帧:

GOAWAY帧:

WINDOW_UPDATE帧:

CONTINUATION帧:

HTTP/3

基于 Google 的 QUIC 协议,它在 HTTP/2 的基础上又实现了质的飞跃,真正“完美”地解决了“队头阻塞”问题。

QUIC 的基本数据传输单位是包(packet)和帧(frame),一个包由多个帧组成,包面向的是“连接”,帧面向的是“流”。

  1. QUIC 是一个新的传输层协议(但不是由操作系统内核实现,不受其限制,而是运行在用户空间),建立在 UDP 之上,实现了可靠传输;

  2. QUIC 内含了 TLS1.3,只能加密通信,支持 0-RTT 快速建连

  3. QUIC 的连接使用“不透明”的连接 ID,不绑定在“IP 地址 + 端口”上,支持“连接迁移”

  4. QUIC 的流与 HTTP/2 的流很相似,但分为双向流和单向流;

  5. HTTP/3 没有指定默认端口号,需要用 HTTP/2 的扩展帧“Alt-Svc”来发现

QUIC : 在UDP上实现的TCP + TLS + HTTP/2的功能

帧结构:

由于流管理被“下放”到了 QUIC,所以 HTTP/3 里帧的结构也变简单了。

为啥没有了流标识字段,那怎么样区分是不是同一个流的数据呢?

HTTPS

HTTPS(HTTP over SSL/TLS)不仅能保证密文传输,重要的是还可以做到验证通信方的身份,保证报文的完整性,HTTPS在内容传输的加密上使用的是对称加密非对称加密只作用在证书验证阶段

TLS / SSL协议位于应用层传输层TCP协议之间

1. 靠近应用层的握手协议(TLS Handshaking Protocols)

  • 密码切换协议 (在TLS1.3中这个协议已经删除,为了兼容TLS老版本,可能还会存在)
  • 警告协议
  • 握手协议
  • 应用数据协议
  • 心跳协议:是TLS1.3新加的,TLS1.3之前的版本没有这个协议

2. 靠近TCP的记录层协议(TLS Record Protocol)

  • 封装处理TLS上层(握手层)中的平行子协议 ( TLS 1 . 3中是5个子协议,TLS 1.2及更老的版本是4个子协议),加上消息头,打包往下传递给TCP处理
  • 对上层应用数据协议进行密码保护,对其他的子协议只是简单封装(即不加密)

传输大致流程: 客户端发起HTTPS请求,服务端返回证书,客户端对证书进行验证,验证通过后本地生成用于改造对称加密算法的随机数,通过证书中的公钥对随机数进行加密传输到服务端,服务端接收后通过私钥解密得到随机数,之后的数据交互通过对称加密算法(使用了双方交换好的随机数对称加密改造)进行加解密。

TLS 的密码套件命名: 密钥交换算法 + 签名算法 + 对称加密算法 + 分组模式 + 摘要算法。

例如: ECDHE-RSA-AES256-GCM-SHA384

加密算法

  1. 对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换,常用的有 AES 和 ChaCha20;

  2. 非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢,常用的有 RSA 和 ECC。(注意:ECC不能直接实现密钥交换和身份验证,需要搭配DH,DSA等算法,形成专门的ECDHE,ECDSA算法,RSA比较特殊,本身即支持密钥交换也支持身份认证)

  3. 把对称加密和非对称加密结合起来就得到了“又好又快”的混合加密,也就是 TLS 里使用的加密方式

摘要算法

在机密性的基础上还必须加上完整性、身份认证等特性,才能实现真正的安全。

实现完整性的手段主要是:摘要算法(Digest Algorithm),也就是常说的散列函数、哈希函数(Hash Function)。

不过摘要算法不具有机密性,如果明文传输,那么黑客可以修改消息后把摘要也一起改了,网站还是鉴别不出完整性。

所以,真正的完整性必须要建立在机密性之上,在混合加密系统里用会话密钥加密消息和摘要,这样黑客无法得知明文,也就没有办法动手脚了。 这有个术语,叫哈希消息认证码(HMAC)

数字签名

分析:加密算法结合摘要算法,我们的通信过程可以说是比较安全了。但这里还有漏洞,就是通信的两个端点(endpoint)。

就像一开始所说的,黑客可以伪装成网站来窃取信息。而反过来,他也可以伪装成你,向网站发送支付、转账等消息,网站没有办法确认你的身份,钱可能就这么被偷走了。

非对称加密里的“私钥”,使用私钥再加上摘要算法,就能够实现“数字签名”,同时实现“身份认证”和“不可否认”。

数字签名的原理其实很简单,就是把公钥私钥的用法反过来,之前是公钥加密、私钥解密,现在是私钥加密、公钥解密。

刚才的这两个行为也有专用术语,叫做“签名”和“验签”

只要你和网站互相交换公钥,就可以用“签名”和“验签”来确认消息的真实性,因为私钥保密,黑客不能伪造签名,就能够保证通信双方的身份。

比如,你用自己的私钥签名一个消息“我是小明”。网站收到后用你的公钥验签,确认身份没问题,于是也用它的私钥签名消息“我是某宝”。你收到后再用它的公钥验一下,也没问题,这样你和网站就都知道对方不是假冒的,后面就可以用混合加密进行安全通信了。

数字证书和 CA

这里还有一个“公钥的信任”问题。因为谁都可以发布公钥,我们还缺少防止黑客伪造公钥的手段,也就是说,怎么来判断这个公钥就是你或者某宝的公钥呢?

这个“第三方”就是我们常说的CA(Certificate Authority,证书认证机构)。它就像网络世界里的公安局、教育部、公证中心,具有极高的可信度,由它来给各个公钥签名,用自身的信誉来保证公钥无法伪造,是可信的。

有了这个证书体系,操作系统和浏览器都内置了各大 CA 的根证书,上网的时候只要服务器发过来它的证书,就可以验证证书里的签名,顺着证书链(Certificate Chain)一层层地验证,直到找到根证书,就能够确定证书是可信的,从而里面的公钥也是可信的。

概括总结

  1. 摘要算法用来实现完整性,能够为数据生成独一无二的“指纹”,常用的算法是 SHA-2;

  2. 数字签名是私钥对摘要的加密,可以由公钥解密后验证,实现身份认证和不可否认;

  3. 公钥的分发需要使用数字证书,必须由 CA 的信任链来验证,否则就是不可信的;

  4. 作为信任链的源头 CA 有时也会不可信,解决办法有 CRL(证书吊销列表,Certificate revocation list)、OCSP(在线证书状态协议,Online Certificate Status Protocol),还有终止信任

HTTP各版本对比

HTTP基于TCP/UDP实现

TCP状态机

解释: 状态转换边的数据含义, 收到信号 / 发送信号 , 其中有些边是同步打开,或者同步关闭的时候建立的

状态:

CLOSED: 表示当前连接已经关闭

LISTEN:表示正在监听中,随时准备接受连接请求

SYN_SENT : 表示已经发送出建立TCP链接的数据包,等待对方回应

SYN_RECVD : 表示接受到了建立TCP链接的数据包,准备给对方发送SYN + ACK

ESTABLISHED : 表示已经建立TCP链接了

FIN WAIT - 1 : 表示主动关闭链接的一方已经发送了FIN包

FIN WAIT - 2 : 表示主动关闭的一方收到了FIN的ACK包, 等待对方发出FIN包

CLOSE WAIT : 表示被动关闭的一方收到了FIN包

LAST ACK : 表示被动关闭的一方发出了FIN包,开始等待对方发送ACK

TIMED WAIT : 表示主动关闭的一方已经发送了ACK,此时主动关闭的一方要等待2倍的max segment lifetime,在此期间,任何因为网络延迟或者拥堵未及时到达的包将会被丢弃,以防下一个链接收到了上一个链接的包

半打开

半打开状态出现在 三次握手阶段,主动建立链接方 和 被动建立链接方都会进入这个状态。

三次握手由 2个 SYN  和 2个 ACK组成,发送出SYN 还没 收到对端的 ACK的状态就是半打开状态,所以主动/被动都可能进入半打开状态。

主动:SYN_SEND, 被动: SYN-RECEIVED

半关闭

半关闭状态出现在 四次挥手阶段,主动关闭链接方 和 被动关闭链接方 都会进入这个状态。

四次挥手由 2个 FIN  和 2个 ACK组成,发送出FIN 还没 收到对端的 ACK的状态就是半关闭状态,所以主动/被动都可能进入半打开状态。

主动:FIN-WAIT-1, 被动: LAST-ACK

TIME_WAIT 不是半关闭状态,此时已经走完四次挥手了; 

CLOSE_WAIT也不是半关闭状态,因为此时作为被动关闭方,其已经收到对端的FIN,此时本端进入CLOSE_WAIT状态,需要应用程序调用close函数来触发对FIN的ACK,并清理资源后发送自己的FIN。只是应用程序没有主动关闭socket套接字(内核socket套接字里面维护了两个缓存区,分别为:读缓缓冲,写缓冲, 读socket发现读到文件结束符,然后调用close函数)。进入此状态,如果不调用close,则四次挥手永远只能停留在第一步,这也会导致主动关闭侧一直处于FIN_WAIT_1状态

三次握手

  • 第一次握手(SYN=1, seq=x),发送完毕后,客户端进入 SYN_SEND 状态

  • 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1), 发送完毕后,服务器端进入 SYN_RCVD 状态。

  • 第三次握手(ACK=1,ACKnum=y+1),发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时, 也进入 ESTABLISHED 状态,TCP 握手,即可以开始数据传输

流程示意图:

为什么需要第3次握手?

第三次握手是为了防止客户端A已失效的连接请求报文段(sync包)传送到B服务器端,因而产生错误的连接建立

具体分析:

正常请求情况

A发出连接请求,但因连接请求报文丢失而未收到确认。于是A再重传一次请求连接。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接。A共发送了两个连接请求报文段。其中第一个丢失,第二个到达了B。

异常请求情况

即A发出的第一个请求连接报文段并没有丢失,而是在某些网络结点长时间滞留了,以至到连接释放以后的某个时间才到达B。本来这是一个已失效的报文段。但B收到此失效的连接请求报文段后,就误认为是A又发出一次新的连接请求。于是就向A发出确认报文段,同意建立连接。假定不采用三次握手,那么只要B发出确认,新的连接就建立了。

由于现在A并没有发出建立请求的连接,因此不会理睬B的确认,也不会向B发送数据,但B却以为新的运输连接已经建立了,并一直等待A发来的数据。B的许多资源就这样白白浪费了。

采用三次握手的话,A不会向B的确认发出确认。B由于收不到确认,就知道A并没有要求建立连接,所以就不会分配资源给这个连接。

四次挥手

  1. 第一次挥手(FIN=1,seq=u),发送完毕后,客户端进入FIN_WAIT_1 状态

  2. 第二次挥手(ACK=1,ack=u+1, seq =v),发送完毕后,服务器端进入CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态

  3. 第三次挥手(FIN=1,ACK=1, seq=w, ack=u+1),发送完毕后,服务器端进入LAST_ACK 状态,等待来自客户端的最后一个ACK。

  4. 第四次挥手(ACK=1,seq=u+1, ack=w+1),客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,自己也关闭连接,进入 CLOSED 状态。服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。

流程示意图:

 等待2MSL的原因

  • 1个 MSL 保证对端没有收到 ACK 那么进行重传的 FIN 报文能够到达

  • 1个 MSL 保证四次挥手中主动关闭方最后的 ACK 报文能最终到达对端

为什么需要4次挥手?

客户端,服务端都需要通知对方,自己要发送的数据都已经发送完了

第一回合挥手: 客户端通知服务端,我没数据要发送了(一来一回,2次)

第二回合挥手: 服务端收到客户端的通知后,处理自己需要发送的数据和操作,等数据发送和操作都全部做完了,然后通知到客户端(一来一回,2次)

抓包命令:tcpdump -i any port 3310 -tttt -nn -X -s0

TCP为什么是可靠的

  • 首先,TCP的连接是基于三次握手,而断开则是四次挥手。确保连接和断开的可靠性。

  • 其次,TCP的可靠性,还体现在有状态;  TCP会记录哪些数据发送了,哪些数据被接受了,哪些没有被接受,并且保证数据包按序到达,保证数据传输不出差错。

  • 再次,TCP的可靠性,还体现在可控制。它有报文校验、ACK应答、超时重传(发送方)、 失序数据重传(接收方)、丢弃重复数据、流量控制(滑动窗口:接收端控制的缓存区)拥塞控制 (发送端控制的拥塞窗口)等机制。

TCP的流量控制

TCP 提供一种机制(滑动窗口)可以让发送端根据接收端的实际接收能力控制发送的数据量,这就是流量控制

TCP的重传机制

有个问题:ACK只向发送端告知最大的有序报文段,到底是哪个报文丢失了呢?并不确定!那到底该重传多少个包呢?

快速重传

S-ACK方法

带选择确认的重传,Selective Acknowledgment

 

D-SACK,

即Duplicate SACK(重复SACK),在SACK的基础上做了一些扩展,,主要用来告诉发送方,有哪些数据包自己重复接受了

 

TCP的拥塞控制

拥塞窗口

发送方维护一个拥塞窗口cwnd(congestion window)的变量,它大小代表着网络的拥塞程度,并且是动态变化的

慢启动(指数递增)

cwnd的值开始为1, 每收到一个ACK,就将拥塞窗口cwnd大小就加1(单位是MSS)

每轮次发送窗口增加一倍,呈指数增长,只要网络中没有出现拥塞,拥塞窗口的值就可以再增大一些,以便把更多的数据包发送出去,但只要网络出现拥塞,拥塞窗口的值就应该减小一些,以减少注入到网络中的数据包数。如果出现丢包,拥塞窗口就减半,进入拥塞避免阶段。

  • TCP连接完成,初始化cwnd = 1,表明可以传一个MSS单位大小的数据。

  • 每当收到一个ACK,cwnd就加一 (每当过了一个RTT,cwnd就增加一倍 ,代表上一个cwnd窗口的所有数据ACK都收到了);  呈指数让升

拥塞避免(线性递增)

cwnd不能无限增下去,使用了一个叫慢启动门限(ssthresh=65536),当cwnd超过该值后,停止慢启动算法,然后开始使用加法线性递增算法

  • 每收到一个ACK时,cwnd = cwnd + 1 / cwnd (即每过一个RTT时,cwnd = cwnd + 1)

拥塞发生

RTO超时重传

  • 慢启动阀值sshthresh =  cwnd / 2

  • cwnd 重置为 1

  • 进入新的慢启动过程

快速重传(重传机制:还包括SACK,D-SACK)

发送方收到3个连续重复的ACK ( 此时是已出现丢包,接收方会连续三次发送重复的ACK) 时,就会快速重传,不必等待RTO超时再重传,快速重传和快速恢复算法一般同时使用。

快速恢复算法认为,还有3个重复ACK收到,说明网络也没那么糟糕,所以没有必要像RTO超时重传表现的那么强烈。

  • 拥塞窗口大小  cwnd = cwnd / 2

  • 慢启动阀值  ssthresh = cwnd

  • 进入快速恢复算法

快速恢复算法

  • cwnd = sshthresh  + 3

  • 重传重复的那几个ACK(即丢失的那几个数据包)

  1. 如果再收到重复的 ACK,那么 cwnd = cwnd +1

  2. 如果收到新数据的 ACK 后,表明恢复过程已经结束,可以再次进入了拥塞避免的算法了。

半连接队列(SYN队列)

TCP三次握手时,客户端发送SYN到服务端,服务端收到之后,便回复ACK和SYN,状态由LISTEN变为SYN_RCVD,此时这个连接就被推入了SYN队列,即半连接队列。

全连接队列(ACCEPT队列)

当客户端回复ACK, 服务端接收后,三次握手就完成了。这时连接会等待被具体的应用取走,在被取走之前,它被推入ACCEPT队列,即全连接队列。

SYN Flood 攻击

SYN Flood是一种典型的DoS (Denial of Service,拒绝服务) 攻击,它在短时间内,伪造不存在的IP地址, 向服务器大量发起SYN报文。当服务器回复SYN+ACK报文后,不会收到ACK回应报文,导致服务器上建立大量的半连接,半连接队列满了,这就无法处理正常的TCP请求了。


END

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JYCJ_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值