网络模型
协议
应用层协议
SMTP协议:提供可靠且有效的电子邮件传输的协议。
FTP协议:TCP/IP网络上两台计算机传送文件的协议,默认情况下FTP协议使用TCP端口中的 20和21这两个端口,其中20用于传输数据,21用于传输控制信息。
网络层协议
ARP协议:根据IP地址获取物理地址的一个TCP/IP协议。
ICMP协议:是一种面向无连接的协议,用于传输出错报告控制信息。
TCP协议
- URG: 表示紧急指针是否有效。
- ACK: 表示确认号是否有效(携带ACK标志的TCP报文段称为确认报文段)。
- PSH: 提示接收端应用程序要立即从TCP接收缓冲区读走数据,以腾出空间接收后续的数据。(若应用 程序不读走数据,数据会一直留在TCP模块的接收缓冲区)。
- RST: 表示要求对方重新建立连接(携带RST标志的TCP报文段为复位报文段)。
- SYN: 表示请求建立一个连接(携带SYN标志的TCP报文段称为同步报文段)。
- FIN: 表示通知对方要关闭连接(携带FIN标志的TCP报文段为结束报文段)。
TCP协议如何保证传输可靠性
- 数据包校验:目的是检测数据在传输过程中的任何变化,若校验出包有错,则丢弃报文段并且不给出响应,这时TCP发送数据端超时后会重发数据;
- 对失序数据包重排序:既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。TCP将对失序数据进行重新排序,然后才交给应用层;
- 丢弃重复数据:对于重复数据,能够丢弃重复数据;
- 应答机制:当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒;
- 超时重发:当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段;
- 流量控制:TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这可以防止较快主机致使较慢主机的缓冲区溢出,这就是流量控制。TCP使用的流量控制协议是可变大小的滑动窗口协议。
三次握手
第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
四次挥手
- 客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
- 服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
- 客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
- 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
- 客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态
- 服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
问题
为什么连接需要三次握手,而挥手需要四次?
答:当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。
为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答:我们必须认为网络是不可靠的,最后一个ACK有可能会丢失,Server如果没有收到ACK,将不断重复发送FIN片段,所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
为什么不能两次握手?
答:网络传输可能延迟,如果只使用两次握手,无法确保数据完整,有序,还会造成不必要的开销。
UDP协议
与TCP协议的区别:
UDP | TCP | |
---|---|---|
是否连接 | 无连接 | 面向连接 |
是否可靠 | 不可靠传输 | 可靠传输,使用流量控制和拥塞控制 |
连接对象个数 | 支持一对一,一对多,多对一和多对多交互通信 | 只能是一对一通信 |
传输方式 | 面向报文 | 面向字节流 |
首部开销 | 首部开销小,仅8字节 | 首部最小20字节,最大60字节 |
适用场景 | 适用于实时应用(QQ、IP电话、视频会议、直播等) | 适用于要求可靠传输的应用,例如文件传输 |
HTTP1.0、HTTP1.1和HTTP2.0
HTTP1.0和HTTP1.1
-
长连接
HTTP1.1开始支持长连接。
-
节约带宽
HTTP1.1支持只发送header信息。
-
HOST域
HTTP1.1必须要求传输HOST域。
-
缓存处理
HTTP1.1引入了更多的缓存控制策略。
-
错误通知的管理
在HTTP1.1中新增了24个错误状态响应码。
HTTP1.1和HTTP2.0
- 多路复用
- 头部数据压缩
- 服务器推送
拥塞控制
当出现丢包事件时,让发送方降低其发送速率,步骤分别有慢启动->拥塞避免>快速恢复。
慢启动
TCP发送方初始阶段不是线性地增加其发送率,而是以指数的速度增加,即每过一个RTT(数据从网络一端传到另一端所需的时间)将cwnd(拥塞窗口)值翻倍。
结束时机:
-
发生一个由超时指示的丢包事件(即拥塞),将ssthresh(阈值)状态变量设为cwnd值的一半,cwnd将设为1个MSS(最大传输大小),并重新开始慢启动。
-
当cwnd的值到达或超过ssthresh时,结束慢启动,TCP转移到拥塞避免模式。
-
若检测到3个冗余ACK,TCP执行快速重传,并进入快速恢复状态。
快速重传:
快重传算法要求首先接收方收到一个失序的报文段后就立刻发出重复确认,而不要等待自己发送数据时才进行捎带确认。
拥塞避免
当cwnd<ssthresh的时候,tcp处于慢启动状态,否则,进入拥塞避免阶段。
拥塞避免的主要思想是加法增大,也就是cwnd的值不再指数级往上升,开始加法增加。此时当窗口中所有的报文段都被确认时,cwnd的大小加1MSS**,即TCP发送方每收到一个新的确认ACK,就将cwnd增加一个MSS/cwnd字节,cwnd的值就随着RTT开始线性增加,这样就可以避免增长过快导致网络拥塞,慢慢的增加调整到网络的最佳值。
结束时机:
-
出现超时,ssthresh被设置为cwnd的一半,cwnd的值被置为1个MSS,进入慢启动。
-
收到3个冗余ACK,ssthresh被设置为cwnd的一半,cwnd为原来的一半加上3个MSS,进入快速恢复状态。
快速恢复
-
当收到3个重复ACK时,把ssthresh设置为cwnd的一半,把cwnd设置为ssthresh的值加3,然后重传丢失的报文段,即ssthresh=cwnd/2,cwnd=ssthresh+3;
-
收到重复的ACK时,cwnd增加1;
-
当收到新的数据包的ACK时,把cwnd设置为第一步中的ssthresh的值,再次进入拥塞避免状态;
-
出现超时,ssthresh被设置为cwnd的一半,cwnd设为1个MSS,进入慢启动状态。
最终呈现锯齿形状:
HTTP状态码
1**:信息,服务器收到请求,需要请求者继续执行操作。
2**:成功,操作被成功接收并处理。
3**:重定向,需要进一步的操作以完成请求。
4**:客户端错误,请求包含语法错误或无法完成请求。
5**:服务器错误,服务器在处理请求的过程中发生了错误。
常见状态码
状态码 | 含义 |
---|---|
100 | 客户端应重新发送初始请求,并在请求中附上第一次请求时未提供的(可能很大或者包含敏感信息的)表示。 |
200 | 表示从客户端发来的请求在服务器端被正确处理。 |
201 | 当服务器依照客户端的请求创建了一个新资源时,发发送此响应代码。 |
204 | 无内容,服务器成功处理了请求,但没有返回任何内容。 |
301 | 永久性重定向,表示资源已被分配了新的 URL。 |
302 | 临时性重定向,表示资源临时被分配了新的 URL。 |
303 | 查看其它位置,表示资源存在着另一个 URL,应使用 GET 方法定向获取资源。 |
304 | 未修改,自从上次请求后,请求的网页未修改过。 |
307 | 临时重定向,和302含义相同。 |
400 | 服务器不理解请求的语法。 |
401 | 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。 |
403 | 服务器拒绝请求。 |
404 | 未找到,服务器找不到请求的网页。 |
409 | 服务器在完成请求时发生冲突,服务器必须在响应中包含有关冲突的信息。 |
500 | 服务器遇到错误,无法完成请求。 |
502 | 服务器作为网关或代理,从上游服务器收到无效响应。 |
504 | 服务器作为网关或代理,但是没有及时从上游服务器收到请求。 |
Select、Poll、Epoll之间的区别
-
select(O(n)时间复杂度)
基于顺序扫描,select本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理,需要无差别轮询所有的数据流,同时,只能监视fd的个数为32位1024个,64位2048个。
-
poll(O(n)时间复杂度)
本质和select没有区别,将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,但是没有最大连接数的限制。
-
epoll(O(1)时间复杂度)
基于事件驱动,流如果发生I/O事件会触发异步回调,可以将时间复杂度降为O(1),同时没有并发数量的限制。
select | poll | epoll | |
---|---|---|---|
操作方式 | 遍历 | 遍历 | 回调 |
底层实现 | 数组 | 链表 | 哈希表 |
IO效率 | 每次调用都进行线性遍历,时间复杂度为O(n) | 每次调用都进行线性遍历,时间复杂度为O(n) | 事件通知方式,每当fd就绪,系统注册的回调函数就会被调用,将就绪fd放到readyList里面,时间复杂度O(1) |
最大连接数 | 1024(x86)或2048(x64) | 无上限 | 无上限 |
fd拷贝 | 每次调用select,都需要把fd集合从用户态拷贝到内核态 | 每次调用poll,都需要把fd集合从用户态拷贝到内核态 | 调用epoll_ctl时拷贝进内核并保存,之后每次epoll_wait不拷贝 |
TCP协议计时器
-
超时重传计时器
目的:避免无限等待确认报文。
创建时间:在发送TCP报文段时,会为该报文段设置一个超时重传计时器。
可能发生的情况:在超时时间到达之前,收到了该报文段的确认则撤销计时器,否则重传该报文段,并将超时重传计时器复位。
重传时间:2*RTT(RTT为往返时间)。
-
坚持计时器
目的:解决零大小窗口导致的死锁问题。
死锁产生原因:当接收端窗口大小为0时,发送端停止发送,此后如果接收端有空余空间来接收数据,则发送一个新窗口大小的报文,如果该报文丢失了则导致双方都处于等待状态,产生死锁。
工作原理:当发送端接收到接收端发送的零大小窗口的报文时,就启动坚持计时器,当计时器到达计时时间,发送端就主动发送一个报文段告诉接收端你发送的新窗口大小的报文丢失了,需要重新发送。
坚持时间 开始先设置为超时重传时间,如果超时了还是没有收到接收端发送的新窗口大小报文,则将计时器的值加倍并且复位,直到大于门限值60s,在此之后每隔60s向接收端发送一个询问报文。
-
保活计时器
目的:避免空闲连接长时间的占用服务器资源。
工作原理:当服务器收到数据时都将保活计时器重新设置(一般2h),过了2h后,服务器如果没有收到数据,每隔75s发送一个探测报文给客户端,当连续发送10次后,仍然没有收到客户端的回复,则服务器断开连接。
-
时间等待计时器(为服务器Time_Wait状态设置)
服务器主动断开连接时,服务器会保持一个Time_wait状态,而时间等待计时器就是Time_wait状态的持续时间。
RTO与RTT
RTO (Retransmission Time Out):重传超时时间,即从数据发送时刻算起,超过这个时间便执行重传。
RTT (Round Trip Time):一个连接的往返时间,即数据发送时刻到接收到确认的时刻的差值。
RTT和RTO 的关系是:由于网络波动的不确定性,每个RTT都是动态变化的,所以RTO也应随着RTT动态变化。
HTTPS建立连接的过程
在浏览器的URL中输入一个HTTPS请求会发生什么?
-
首先进行域名解析,域名解析具体过程讲一下:
-
浏览器搜索自己的DNS缓存,缓存中维护一张域名与IP地址的对应表;
-
若没有,则搜索操作系统的DNS缓存;
-
若没有,则操作系统将域名发送至本地域名服务器(递归查询方式),本地域名服务器查询自己的DNS缓存,查找成功则返回结果,否则,通过以下方式迭代查找:
-
本地域名服务器向根域名服务器发起请求,根域名服务器返回com域的顶级域名服务器的地址;
本地域名服务器向com域的顶级域名服务器发起请求,返回权限域名服务器地址;
本地域名服务器向权限域名服务器发起请求,得到IP地址。
本地域名服务器将得到的IP地址返回给操作系统,同时自己将IP地址缓存起来; 操作系统将IP地址返回给浏览器,同时自己也将IP地址缓存起来; 至此,浏览器已经得到了域名对应的IP地址。
-
-
浏览器发起HTTP请求;
-
接下来到了传输层,选择传输协议,TCP或者UDP,TCP是可靠的传输控制协议,对HTTP请求进行封装,加入了端口号等信息;
-
然后到了网络层,通过IP协议将IP地址封装为IP数据报;然后此时会用到ARP协议,主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址,找到目的MAC地址;
-
接下来到了数据链路层,把网络层交下来的IP数据报添加首部和尾部,封装为MAC帧,现在根据目的mac开始建立TCP连接,三次握手,接收端在收到物理层上交的比特流后,根据首尾的标记,识别帧的开始和结束,将中间的数据部分上交给网络层,然后层层向上传递到应用层;
-
服务器响应请求并请求客户端要的资源,传回给客户端;
-
断开TCP连接,浏览器对页面进行渲染呈现给客户端。