即一系列协议所组成的一个网络分层模型
网络分层
为什么要分层?
因为网络的不稳定
- 应用层:主要有负责web浏览器的HTTP协议, 文件传输的FTP协议,负责电子邮件的SMTP协议,负责域名系统的DNS等。
- Http协议
- 传输层:主要负责传输应用层的数据包。
- 可靠传输的TCP协议,数据分块组装(较大的数据)
- 特别高效的UDP协议,直播游戏等不需要重传数据,
- 网络层:主要是IP协议,主要负责寻址(找到目标设备的位置)
- IP协议 以最小单位发送和接收分块的网络数据
- 数据链路层:主要是负责转换数字信号和物理二进制信号。
- 以太网,wifi等
数据传输过程
数据链路层>网络层>传输层>应用层,一层层的解码,最后就可以在浏览器中得到目标设备传送过来的index.html
四层网络协议的作用
TCP/IP是指为互联网而开发制定的协议族,并非仅单指TCP协议和IP协议。
- 发送端是由上至下,把上层来的数据在头部加上各层协议的数据(部首)再下发给下层。
- 接受端则由下而上,把从下层接受到的数据进行解密和去掉头部的部首后再发送给上层。
- 层层加密和解密后,应用层最终拿到了需要的数据。
osi七层网络模型与TCP/IP四层网络模型
- OSI 七层模型是学术界提出的,从层数上就知道它更把网络分的更加详实,从而也使得它的实现更加复杂,因此它的学术价值更大。 而 TCP/IP 网络模型是由计算机寡头提出并实现,是OSI 七层模型的简化版;属于开源产品,能直接提供给用户使用。
- 四层模型属于工业标准,是将 OSI 的有一些层被整合(应用层、表示层和会话层合并为应用层,数据链路层和物理层合并为网络接口层),或者功能分散到其他层去,因此在实际应用中更广泛。
- 五层模型只是在学习计算机网络原理是往往采用的折中办法,因为 OSI 七层模型层数过多,太详细了反倒不适合学习,四层模型过于简化,于是综合OSI和TCP/IP的优点而提出五层模型,这样既简洁又能将概念阐述清楚(总不能一会学习 OSI 一会又来学习 TCP/IP 四层模型吧)。
从图中可以看到,四层模型最底下两层总是有不同的名称,我们搞明白这两层的任务更重要。
- 第一层主机到网络层,也叫网络接口层,负责监视数据在主机和网络之间的交换,即接收来自网络互联层的数据包并通过网络发送出去,或者从网络上接收物理帧,抽出 IP 数据报,交给网络互连层;它对应的是 OSI 七层模型中数据链路层和物理层。 在 TCP/IP 四层模型中并未定义该层的协议,而是由参与互连的各网络使用自己的物理层和数据链路层协议,这里为什么要提到“各网络”?因为数据链路从和物理层直接跟硬件打交道,而不同的网络类型使用的底层协议往往不一致,比如按传输介质区分的有线网(双绞线/同轴电缆)、无线网、光线网等,由于信号、频率等的差别,它们的数据解析协议肯定不一样。
- 网络互联层,又称网际互联层,顾名思义,是网络间的通信,它是整个 TCP/IP 协议栈的核心,其功能是把分组发往目标网络或主机。这一层需要解决拥塞控制问题。
附录:
TCP 和 UDP 的区别
- TCP 是面向连接的,udp 是无连接的即发送数据前不需要先建立链接。
- TCP 保证数据正确性,UDP 可能丢包,TCP 保证数据顺序,UDP 不保证。也就是说,通过 TCP 连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP 尽最大努力交付,即不保证可靠交付 Tcp 通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。
- TCP 只能是 1 对 1 的,UDP 支持 1 对 1,1 对多。
- TCP 是面向字节流,UDP 面向报文,UDP 具有较好的实时性,工作效率比 TCP 高.并且网络出现拥塞不会使得发送速率降低(因此会出现丢包,对实时的应用比如 IP 电话和视频会议等)。
- TCP 对系统资源要求较多,UDP 对系统资源要求较少。
- TCP 的首部较大为 20 字节,而 UDP 只有 8 字节。
TCP连接
连接:指的是TCP的连接
- HTTP是无状态的
- TCP是有状态的交互
三次握手和四次挥手
上图中有几个字段需要重点介绍下:
- (1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
- (2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。(千万不要与标志位中的ACK搞混,这两个不是一个东西)
- (3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:
- SYN:请求建立连接,并在其序列号的字段进行序列号的初始值设定。建立连接,设置为 1
- ACK:确认序号是否有效,一般置为1。
- FIN:释放一个连接。
- PSH:提示接收端应用程序立即从 TCP 缓冲区把数据读走。接收方应该尽快将这个报文交给应用层。
- RST:重置连接。对方要求重新建立连接,复位。
- URG:紧急指针(urgent pointer)有效。
TCP连接的建立:三次握手
第一次握手:
客户端向服务器发出连接请求报文,这时报文首部中的同部位SYN=1,同时随机生成初始序列号 seq=x,此时,TCP 客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP 规定,SYN 报文段(SYN=1 的报文段)不能携带数据,但需要消耗掉一个序号。这个三次握手中的开始。表示客户端想要和服务端建立连接。
第二次握手
TCP服务器收到请求报文后,如果同意连接,则发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己随机初始化一个序列号 seq=y,此时,TCP 服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号。这个报文带有SYN(建立连接)和ACK(确认)标志,询问客户端是否准备好。
第三次握手
TCP客户进程收到确认后,还要向服务器给出确认。确认报文的 ACK=1,ack=y+1,此时,TCP 连接建立,客户端进入ESTABLISHED(已建立连接)状态。TCP 规定,ACK 报文段可以携带数据,但是如果不携带数据则不消耗序号。这里客户端表示我已经准备好。
最后默写一遍
1. 客户端:「我要向你发送消息」
2. 服务器:「好的。我要向你发送消息」
3. 客户端:「好的。
为什么要三次握手
在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。在另一部经典的《计算机网络》一书中讲“三次握手”的目的是为了解决“网络中存在延迟的重复分组”的问题。
在谢希仁著《计算机网络》书中同时举了一个例子,如下:
“已失效的连接请求报文段”的产生在这样一种情况下:client 发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达 server。本来这是一个早已失效的报文段。但 server 收到此失效的连接请求报文段后,就误认为是 client 再次发出的一个新的连接请求。于是就向 client 发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要 server 发出确认,新的连接就建立了。由于现在 client 并没有发出建立连接的请求,因此不会理睬 server 的确认,也不会向 server 发送数据。但 server 却以为新的运输连接已经建立,并一直等待 client 发来数据。这样,server 的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client 不会向 server 的确认发出确认。server 由于收不到确认,就知道 client 并没有要求建立连接。”
总结一下就是为了防止服务端的等待浪费资源。
TCP连接的关闭:四次挥手
第一次挥手
服务端收到这个 FIN,他发回一个 ACK(确认),确认收到序号为收到序号+1,和 SYN 一样,一个 FIN 将占用一个序号。
服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号 seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP 服务器
通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个 CLOSE-WAIT 状态持续的时间。
客户端收到服务器的确认请求后,此时,客户端就进入 FIN-WAIT-2(终止等待 2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
第三次挥手
服务端发送一个 FIN(结束)到客户端,服务端关闭客户端的连接。
服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为 seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
第四次挥手
客户端发送 ACK(确认)报文确认,并将确认的序号+1,这样关闭完成。
客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是 seq=u+1,此时,客户端就进入了 TIME-WAIT(时间等待)状态。注意此时 TCP 连接还没有释放,必须经过 2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的 TCB 后,才进入 CLOSED 状态。
服务器只要收到了客户端发出的确认,立即进入 CLOSED 状态。同样,撤销 TCB 后,就结束了这次的 TCP 连接。可以看到,服务器结束 TCP 连接的时间要比客户端早一些。
最后默写一遍
1. 客户端:「我不再给你发送消息」
2. 服务端:「好的」
3. 服务端:「我不再给你发送消息」
4. 客户端:「好的」
常见问题
①为什么要三次握手(两次握手可以吗?)
client 发送了第一个连接的请求报文,但是由于网络不好,这个请求没有立即到达服务端,而是在某个网络节点中滞留了,直到某个时间才到达 server,本来这已经是一个失效的报文,但是 server 端接收到这个请求报文后,还是会想 client 发出确认的报文,表示同意连接。假如不采用三次握手,那么只要 server 发出确认,新的建立就连接了,但其实这个请求是失效的请求,client 是不会理睬 server 的确认信息,也不会向服务端发送确认的请求,但是 server 认为新的连接已经建立起来了,并一直等待 client 发来数据,这样,server 的很多资源就没白白浪费掉了,采用三次握手就是为了防止这种情况的发生,server 会因为收不到确认的报文,就知道 client 并没有建立连接。这就是三次握手的作用。
简单来说,就是为了防止服务端的等待浪费资源
②为什么是 4 次挥手
握手的时候,A 和 B 打个招呼,B 可以直接把自己的 SYN 信息和对 A 的回应 ACK 信息一起带上,但是挥手的时候,A 说我要断开了,B 还没发完最后的数据,因此需要先回应一下 A,我收到你的断开的请求了,但是你要等我把最后的内容给你,所以这里分开了 2 步:
(1)回应 A;
(2)发送自己的最后一个数据
为了确保数据能够完成传输。
③客户端突然挂掉了怎么办
正常连接时,客户端突然挂掉了,如果没有措施处理这种情况,那么就会出现客户端和服务器端出现长时期的空闲。解决办法是在服务器端设置保活计时器,每当服务器收到客户端的消息,就将计时器复位。超时时间通常设置为 2 小时。若服务器超过 2 小时没收到客户的信息,他就发送探测报文段。若发送了 10 个探测报文段,每一个相隔 75 秒,还没有响应就认为客户端出了故障,因而终止该连接。
设置保活计时器
④为什么 TIME_WAIT 状态需要经过 2MSL(最大报文段生存时间)才能返回到 CLOSE 状态
TIME_WAIT 状态就是用来重发可能丢失的 ACK 报文 原因是,担心网络不可靠而导致的丢包,最后一个回应 B 的 ACK 万一丢了怎么办,在这个时间内,A 是可以重新发包的,但是超过了最大等待时间的话,就算收不到也没用了,所以就可以关闭了。
⑤浏览器同时可以开启多少个 http 链接
浏览器对于同一个域名,一般 PC 端浏览器会针对单个域名的 server同时建立 6 ~ 8 个连接,手机端的连接数则一般控制在4 ~ 6 个(这个根据浏览器内核不同可能会有所差异),超过浏览器最大连接数限制,后续请求就会被阻塞。
长连接与短连接
短连接
概念:如下图所示,客户端与服务器建立连接开始通信,一次/指定次数通信结束之后就断开本次TCP连接,当下次再次通信时,再次建立TCP的链接
优点:不长期占用服务器的内存,那么服务器能处理的连接数量是比较多的
缺点:
- 因为等到要发送数据或者获取资源时,才去请求建立连接发送数据,否则就是端开连接的,那么**如果服务器要想往客户端发送数据时怎么办?**凉伴,没有任何办法,或者要等到下一次要请求数据时,才发送,比如我们采用轮询(30秒或者更长)拉取消息, 那么服务器与客户端通信的实时性就丧失了
- 客户端采用轮询来实时获取信息,或者说大量的客户端使用短连接的方式通信,那么就浪费了大量的CPU和带宽资源用于建立连 接和释放连接,存在资源浪费,甚至是无法建立连接。比如经典的http长轮询(微信网页客户端端)
长连接
概念:如下图所示,TCP与服务器建立连接之后一直处于连接状态,直到最后不再需要服务的时候才断开连接
优点:
- 传输数据快
- 服务器能够主动第一时间传输数据到客户端
缺点:
- 因为客户端与服务器一直保持这种连接,那么在高并发分布式集群系统中客户端数量会越来越多,占 用很多的系统资源
- TCP本身是一种有状态的数据,在高并发分布式系统会导致后台设计比较难做
为什么需要长连接
- 服务器要主动发消息给客户端:如果没有一个连接存在的话,服务器是永远不能主动地找到客户端的,那也就没有办法及时发送消息给客户端
- 客户端和服务器间频繁地通信:如果是短连接,每次都需要建立连接才能发送消息,如果并发量稍高,可能就会出现大量的TIME_WAIT状态的socket出现,也即后续建立不了连接
- 业务需要,比如客户端掉线时服务器需要做一些处理:比如清空他的缓存或者其它资源或者其它业务含义,比如QQ头像显示离线
TCP长连接设计时需要考虑到的问题
- 默认的tcp keep-alive超时时间太长:默认是7200秒,也就是2个小时,当然是可以修改的
- socket proxy会让tcp keep-alive失效:所有的proxy应用只能转发TCP的应用数据,做不到转发TCP协议内部的包
- 移动网络需要信令保活:对于手机等智能终端来讲,他们使用移动网络来上网的,而运营商们为了节约信道资源,会尝试关闭超过60秒或者 45秒的没有发送数据的socket
心跳检测(长连接实现方式)
心跳检测就是用户在应用层自己实现的一种机制,用来模仿TCP的keepalive机制,在指定的时间内会向对方放一个心跳检测包,如果在指定的时间内给自己回送了应答,那么就不关闭TCP的连接;如果在指定的时间内没有给自己回送应答,那么就做相应的处理(例如说的关闭本次TCP的链接)
Netyy中的实现