基础知识
主机通信
- C/S:客户端-服务器
- P2P:对等,不区分客户端和服务器
电路交换和分组交换
电路交换中,两个用户通信之前要建立一条专用的物理链路,并且通信过程中始终占用该链路,利用率很低。
分组交换中,每个分组都有首部和尾部,包含了源地址和目的地址等控制信息,同一个传输线路上同时传输多个分组互相不会影响。
计算机网络体系结构
应用层
应用层通过应用进程间的交互来完成特定网络应用。应用层协议定义应用进程间的通信和交互规则。
应用层协议有域名系统DNS,万维网应用HTTP协议,支持电子邮件的SMPT协议,文件传输协议FTP,远程登录协议TELNET
应用层交互的数据单元称为报文。
传输层
传输层的主要任务是负责向两台主机进程之间的通信提供通用的数据传输服务。所谓通用就是指多种应用协议可以使用同一个运输层服务。
- 复用:在发送端,多个应用进程共用一个传输层。
- 分用:在接收端,传输层根据端口号将数据分派给不同的应用进程。
运输层主要使用以下两种协议:
- TCP:面向连接,可靠的数据传输服务,数据单位为报文段。主要提供完整性服务。
- UDP:面向无连接,尽最大努力的数据传输服务,数据单位为用户数据报。主要提供及时性服务。
网络层
为主机提供数据传输服务,与之对比,传输层是为主机中的进程提供数据传输服务。
在网络中通信的两个计算机之间可能会经过很多数据链路、通信子网,网络层的任务就是选择合适的路由和交换节点,确保数据及时传送。
网络层把运输层产生的报文段(TCP)或用户数据报(UDP)封装成分组和包进行传送。网络层使用IP协议,因此分组也称为IP数据报,简称数据报。
- 网络层为不同主机提供通信服务,传输层为不同主机的不同应用提供通信服务。
- 网络层只对报文头部进行差错检测,传输层对整个报文进行差错检测。
数据链路层
为同一链路的主机提供数据传输服务。数据链路层把网络层传下来的分组封装成帧。
物理层
在物理层上所传送的数据单位是比特。 物理层(physical layer)的作用是实现相邻计算机节点之间比特流的透明传送,尽可能屏蔽掉具体传输介质和物理设备的差异。 使其上面的数据链路层不必考虑网络的具体传输介质是什么。
图片来源:https://blog.youkuaiyun.com/yaopeng_2005/article/details/7064869
网络层
网络层不提供服务质量的承诺,不保证分组交付的时限锁传送的分组可能出错,丢失,重复和失序。进城之间通信的可靠性靠运输层负责。
IP地址划分
传输层
传输层提供了进程间的逻辑通信,传输层向高层用户屏蔽了下面网络层的核心细节,使应用程序看起来像是在两个传输层实体之间有一条端到端的逻辑通信信道。
TCP协议
- 面向连接:通信前需要建立连接、通信结束需要释放连接。
- 提供可靠交付:TCP发送的数据无重复、无丢失、无错误,与发送端顺序一致。
- 面向字节流:TCP以字节为单位,传输过程中数据被划分成数据报。
- 提供全双工通信:TCP两端既可以作为发送端、也可以作为接受端。
- 连接的两端只能是一对一、点对点的。TCP只能提供点到点的通信,UDP可以任意方式的通信。
TCP头部
- 序号:用于对字节流进行编号
- 确认号:期望收到的下一个报文段的序号
- 数据偏移:首部长度
- ACK:确认,ACK=1时确认号字段有效,否则无效。TCP规定在连接建立后所有传送的报文段都要把ACK置为1。
- SYN: 同步,在连接建立时用来同步序号。SYN=1,ACK=0表示连接请求报文段。若对方同意建立连接,则响应报文中SYN=1,ACK=1。
- FIN: 终止,用来释放一个连接,当FIN=1时,表示此报文段的发送方的数据已经发送完毕,并要求释放连接。
- 窗口:窗口值作为接收方让发送方设置其发送窗口的依据。因为接收方的缓冲空间是有限的。
三次握手
起初,服务器和客户端都是CLOSED状态。服务器随后进入LISTEN状态,准备接收客户端传来的连接请求。
第一次握手
客户端向服务器端发送连接请求报文段,请求发送后,客户端进入SYN-SENT状态。
- SYN=1, ACK=0 表示该报文段为连接请求报文。
- seq=x 表示本次TCP通信的字节流的初始序号
- TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。
第二次握手
服务端收到连接请求报文段后,如果同意连接,发送一个应答,应答发送完成后进入 SYN-RCVD 状态。
- SYN=1, ACK=1 表示该报文段是连接同意的应答报文
- 这个报文也不能携带数据,但是同样要消耗一个序号。
- seq=y 表示服务端作为发送者时,发送字节流的初始序号
- ack=x+1 表示服务端希望下一个数据报发送序号从 x+1 开始的字节
第三次握手
客户端收到连接同意的应答后,还要向服务端发送一个确认报文段,表示服务端发来的连接同意应答已经成功收到。
客户端发完这个报文段后进入 ESTABLISHED 状态,服务端收到这个应答后也进入 ESTABLISHED 状态,此时连接建立完成。
三次握手的原因
主要防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误。
如果使用的是两次握手建立连接,假设有这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费。
如果采用的是三次握手,就算是那一次失效的报文传送过来了,服务端接受到了那条失效报文并且回复了确认报文,但是客户端不会再次发出确认。由于服务器收不到确认,就知道客户端并没有请求连接。
第一次握手中,S确认了C方发送正常。第二次握手中,C确认了自己发送、接收正常,对方发送、接收正常;S确认了自己接收正常,对方发送正常。第三次握手中,C确认自己发送、接收正常,对方发送、接收正常;S确认了自己发送、接收正常,对方发送接收正常。
四次挥手
在四次挥手中,前两次挥手用于断开一个方向的连接,后两次挥手用来断开另一方向的连接。
第一次挥手
当A认为数据发送完成,向B发送连接释放请求,发送完毕后A进入FIN-WAIT-1状态。
- 该请求只有报文头
- FIN=1表示该报文段是一个连接释放请求
- seq=u,是A向B发送的最后一个字节的序号加上1
- TCP规定,FIN报文段即使不携带数据,也要消耗一个序号
第二次挥手
B收到连接释放请求后,会通知相应的应用程序,告诉它A向B这个方向的连接已经释放,然后向A发送连接释放的应答,并进入CLOSE-WAIT状态。
- ACK=1:除TCP连接请求报文段之外,所有TCO数据报的ACK都为1,表示应答。
- seq=v, 是B向A发送的最后一个字节的序号加1
- ack=u+1,表示希望收到从u+1开始的报文段,且已经成功接收了前u个字节
A收到应答,进入FIN-WAIT-2状态,等待B发送连接释放请求。
第二次挥手完成后,A到B方向的连接已经释放,B不会再接收数据,A也不会再发送数据。但是B到A的连接仍然存在。
第三次挥手
B向A发送完所有数据后,向A发送连接释放请求,然后进入LAST-ACK状态。 请求头为 FIN=1,ACK=1,seq=w,ack=u+1。
第四次挥手
A收到释放请求后,向B发送确认应答,此时A进入TIME-WAIT状态,持续2MSL(最长报文段寿命)时间。如果期间没有B的重发请求,进入CLOSED。B收到确认应答,也进入CLOSED。
等待2MSL的原因
- 保证客户端发送的最后一个ACK能到达服务器,因为这个ACK报文可能丢失,因此服务器可能会重传,客户端在2MSL时间段内收到这个重传报文,接着给出回应报文,并且重启2MSL计时器。否则,服务端重传,客户端已经关闭了,服务端无法正常关闭。
- 客户端发送完最后一个确认报文后,在2MSL时间内,就可以使本链接持续时间内所产生的所有报文段都从网络中小时,这样新连接中不会出现旧连接的请求报文。
四次挥手的原因
建立连接时,服务器LISTEN状态下,收到请求建立连接的SYN保温后,将ACK和SYN放在一个报文里发送给客户端。关闭连接时,服务器收到对方FIN报文时,仅仅表示对方不再发送数据,但是还能接收数据,而自己也未必全部数据都发送给对方了。因此FIN和ACK分开发送,导致多了一次。
如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75分钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
TCP可靠传输
TCP 使用超时重传来实现可靠传输。如果一个已经发送的报文段在超时时间呃逆没有收到确认,那么就重传这个报文段。
滑动窗口协议
窗口是缓存的一部分,用来暂时存放字节流。发送方和接收方各有一个窗口,接收方通过TCP报文段中窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其他信息设置自己的窗口大小。
发送者可以在没有得到应答的情况下连续发送窗口中的分组。接受者也有一个接收窗口,可以连续收到分组后统一返回一个应答。TCP头部的ack字段用来累计确认,表示已经确认的字节序号加上1,也表示期望发送者发送的下一个分组的起始字节号。
发送窗口 发送窗口大小由接收窗口的剩余大小决定。接收方会把当前接收窗口剩余大小写入应答TCP报文头部,发送方根据该值以及当前网络拥塞情况设置发送窗口的大小,发送窗口大小不断变化。 接收窗口 接受者会对已经正确接收的有序字节进行累计确认,发送完确认应答后,接收窗口就可以向前移动指定字节。如果某些字节未按顺序收到,接收者只会确认最后一个有序的字节。
流量控制
TCP 利用滑动窗口实现流量控制。
流量控制是为了控制发送方发送速率,保证接收方来得及接收。如果发送者发送过快,接收者来不及接收,那么就会有分组丢失。为了避免分组丢失,控制发送者的发送速度,使得接收者来得及接收,这就是流量控制。
流量控制目的是防止分组丢失,它是构成TCP可靠性的一方面。
拥塞控制
拥塞控制的目的是缓解网络压力,保证分组按时到达。
为了进行拥塞控制,TCP 发送方要维持一个 拥塞窗口(cwnd) 的状态变量。拥塞控制窗口的大小取决于网络的拥塞程度,并且动态变化。发送方让自己的发送窗口取为拥塞窗口和接收方的接受窗口中较小的一个。
TCP通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复。
- 慢开始和拥塞避免
发送最初执行慢开始,令 cwnd = 1;收到确认后,将其加倍,因此发送方能发送的报文段数量为:2,4,8,... 同时,设置一个慢开始门限ssthresh,当cwnd>=ssthresh时,进入拥塞避免,每次只增加1。
如果出现超时,令ssthresh=cwnd/2,重新执行慢开始。
- 快重传与快恢复
在发送方,如果收到三个重复确认,那么可以知道下一个报文段丢失,此时执行快重传,立即重传下一个报文段。例如收到三个 M2,则 M3 丢失,立即重传 M3。
此时网络已经出现拥塞的征兆,因此执行快恢复,令慢启动门限减半,发送窗口减半,使用拥塞避免算法。
UDP协议
- UDP 只在 IP数据报服务的基础上增加了少量的功能:复用与分用、对整个报文的差错检测。
- UDP是无连接的:通信前不需建立连接,结束无需释放连接
- UDP是不可靠的:尽力而为,不保证每个数据报都能送达
- UDP是面向报文的:UDP数据传输的单位是报文,不会对数据做任何拆分和拼接。发送端,UDP只对应用程序的数据添加一个UDP头并交给网络层;接收端,UDP收到网络层的数据报后,去除IP数据报头部后遍交给应用层,不会作任何拼接操作。
- UDP没有拥塞控制:UDP始终以恒定的速率发送数据。弊端是拥塞时报文可能丢失;优点是实时性好
- UDP支持一对一、一对多、多对多、多对一通信
- UDP首部开销小,只有8字节,TCP至少20字节。
HTTP协议
HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。
报文
请求报文
响应报文
状态码
- 100 Continue:目前为止正常
- 200 OK
- 301 Moved Permanently:永久重定向
- 302 Found:临时重定向
- 303 See Other:与302类似,303要求客户端采用GET方法
- 400 Bad Request:请求报文中存在语法错误
- 401 Unauthorized
- 403 Forbidden
- 404 Not Found
- 500 Internal Server Error:服务器执行请求时发送错误
- 503 Service Unavailable:服务器现在无法处理请求
Cookie
HTTP/1.1 引入 Cookie 来保存状态信息。Cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带上,用于告知服务端两个请求是否来自同一浏览器。
Session
用户信息还可以利用Session存储在服务器端,可以存储在服务器上的文件、数据库或者内存中。也可以将Session存储在Redis这种关系型数据库中,效率更高。
比较
- Cookie 只能存储 ASCII 码字符串,而 Session 则可以存取任何类型的数据,因此在考虑数据复杂性时首选 Session;
- Cookie 存储在浏览器中,容易被恶意查看。如果非要将一些隐私数据存在 Cookie 中,可以将 Cookie 值进行加密,然后在服务器进行解密;
- 对于大型网站,如果用户所有的信息都存储在 Session 中,那么开销是非常大的,因此不建议将所有的用户信息都存储到 Session 中。
HTTP/2.0
HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式的。在通信过程中,只会有一个 TCP 连接存在,它承载了任意数量的双向数据流(Stream)。
服务端推送 在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。
首部压缩 HTTP/1.1 的首部带有大量信息,而且每次都要重复发送。 HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见过的首部字段表,从而避免了重复传输。 不仅如此,HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。
GET和POST比较
- GET用于获取资源,POST用于传输实体主体。
- 两者都能使用额外参数,GET参数以查询字符串出现在URL中,只支持ASCII码,因此需要进行编码;POST参数存储在实体主体中,但是同样可以被抓包工具查看,也不是很安全。
- GET方法不会改变服务器状态,POST可能会改变。
- GET方式提交的数据大小由限制,因为URL长度有限制,POST没有此限制。
HTTP长连接、短连接
在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。
而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。
在浏览器中输入URL地址到显示的过程
- DNS解析
- 建立TCP连接
- 发送HTTP请求
- 服务器处理请求并返回HTTP报文
- 浏览器解析渲染页面
- 连接结束
HTTPS协议
HTTP存在安全性问题:
- 使用明文通信,内容可能被窃听
- 不验证通信方身份,可能遭遇伪装
- 无法证明报文的完整性,报文可能遭到篡改
HTTPS 是让HTTP先和SSL/TLS通信,再由SSL/TLS和TCP通信,使用了隧道进行通信。通过使用SSL,具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。
- 客户端发起HTTPS请求(443端口)
- 服务端配置(证书,也即一对公钥和私钥)
- 传递证书(公钥)
- 客户端解析证书(TLS完成,验证公钥是否有效,有效后生成随机值,用证书对随机值加密)
- 传递加密信息(传递加密后的随机值)
- 服务器解密信息(用私钥解密后,得到客户端传来的随机值也就是私钥,然后把内容通过该值进行对称加密)
- 传输加密后的信息
- 客户端解密信息