TCP/IP协议
核心主旨
计算机之间是如何有效地进行连接和沟通,就是由于网络协议来定义和发送的。
网络基本模型
A机器 | 协议 | B机器 |
---|---|---|
应用层 | HTTP/FTP | 应用层 |
传输层 | TCP/UDP | 传输层 |
网络层 | IP | 网络层 |
链路层 | IEEE802.X | 链路层 |
物理层 | 网卡 | 物理层 |
- 链路层:就是链路层报头+帧上数据(前者是为了标识物理层信息,后者是为了往上传的信息)
链路层报头 | 帧上数据 |
---|---|
本机MAC地址 | IP报头 |
目标MAC地址 | IP数据(TCP报头+数据) |
网络层协议 | 校验码 |
-
网络层:子网内根据地址解析协议进行MAC寻址,子网外通过路由转发IP数据包。同时加入IP地址的概念
-
传输层:定义逻辑接口,确认身份后,将数据包交给应用程序,实现端口之间的通信。
-
应用层:传输层的数据到达应用程序后,以某种统一规定的协议格式来解读数据。
计算机之间的通讯
程序在发送信息时,应用层按照既定的协议打包数据,由传输层加上双方的端口号,由网络层加上双方的IP地址,由链路层加上双方的MAC地址,并将数据拆分为数据帧,经过多个路由器和网关后,到达目标机器。
IP协议
为什么MAC地址可以标识主机,还需要使用IP地址来寻找主机呢?
通过广播寻找MAC地址太难,不可能做到完全不超时,因此IP地址就是通过对地址进行分层管理来实现快速寻找主机地址。
IP服务的特点
IP协议是TCP/IP协议族的基石,它为上层提供无状态、无连接、不可靠的服务
无状态:指IP通信双方不同步传输数据的状态信息,因此所有IP数据报的发送,传输,接收都是相互独立的。这种服务最大缺点是无法处理乱序和重复的IP数据报。优点是简单高效,和UDP协议与HTTP协议相同,都是无状态协议。
无连接:指IP通信双方都不长久的维持对方的任何信息。这表示上层协议每次发送数据,都需要明确指定对方的IP地址。
不可靠:指IP协议不能IP数据报能准确到达接收端,只是会尽最大努力。一旦发送失败,就通知上层协议,而不会试图重发
IP报文格式
数据包生存时间:数据报到达目的地之前允许经过的路由器跳数。每经过一个路由,该值减一,为0时被丢弃。并返回TCMP错误报文。
IP层的工作流程
IP模块收到来自数据链路层的IP数据报,首先对数据报的头部做CRC校验,无误后开始分析头部具体信息。
如果IP数据报头部设置了源站选路选项,则IP模块调用数据报转发子模块来处理该数据报。
如果该数据报的头部目标IP地址是本机的某个IP地址,或者广播地址,则IP模块根据数据报协议字段来决定发送给哪个上层应用。如果不是本机,则掉用数据报转发子模块来处理该数据报。
数据报转发模块检查系统是否允许转发,不允许则丢弃。允许则将该数据报执行一些操作,就将它交给IP数据报输出模块。
IP数据报根据路由表计算下一跳路由。
UDP协议(User Datagram Protocol)
传输层上的协议,与IP协议一样,UDP协议的三个特征:
- 无连接:发送数据之前不需要建立链接
- 不可靠:不保证可靠交付
- 无状态:接收方和发送方相互独立
UDP是面向报文的:
发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层。UDP 对应用层交下来的报文,既不合并,也不分拆,而是保留这些报文的边界。这就是说,应用层交给 UDP 多长的报文,UDP 就照样发送,即一次发送一个报文,如图 5-4 所示。在接收方的 UDP,对 IP 层交上来的 UDP 用户数据报,在去除首部后就原封不动地交付上层的应用进程。
注意
虽然 在 UDP 之间的通信要用到其端口号,但由于 UDP 之间的通信是无连接的,因此不需要使用套接字socket(TCP 之间的通信必须要在两个套接字之间建立连接)——TCP必须要区分服务器端和客户端的概念。
TCP协议(Transmission Control Protocol)
TCP与UDP区别
结论是TCP更加可靠安全,因为UDP仅仅智能保证数据包从一台主机发送到另一台主机,不能保证数据能够安全到达。而TCP在传输层中建立了高可靠性的端对端通信机制。
什么是可靠性
- TCP会尽自己所能,尽量将数据发送给对方;但并不能保证100%可以发送给对方
- TCP会在数据发送不到对方的情况下,会给应用层一个错误提示,告知用户发送失败
- TCP可以保证接收方(应用层)严格按照发送时的数据顺序接收
- TCP保证数据不会出现无意间的损坏(UDP 也做到这点)
- TCP尽可能地维护网络质量
TCP报文格式
原机器和目标机器的端口号和源IP地址和目标IP地址所组成的四元组可以唯一标识一条TCP连接。
(端口号即为网络编程时的服务器端和客户端监听机制)
序列号是指所发送数据包中数据部分的第一个字节的序号,确认序号则是指期望收到对方的下一个数据包中数据部分的第一个字节的序号。起始序列号为初始序列号(ISN)
三次握手机制
几个基础概念
序列号
SN(Sequence Number):序列号,即发送的数据编号(数据部分的第一个字节)
ASN(Ackonwledge Sequence Number ):确认序列号
ISN(Initial SN):初始序列号
标识码
SYN(Synchronize Sequence Numbers):用于建立连接的同步信号
ACK(Acknowledgement):对收到的数据进行确认
FIN(Finish)表示后面没有数据需要发送,意味着建立的连接需要关闭了
缓冲区
TCP是有发送缓冲区的,用于暂时保存已发送,未应答的数据(方便重发)
TCP也有接收缓冲区,是因为接收到的信息,不一定马上就能被应用层取走
示意图
流程解释
三次握手的机制是为了保证能建立一个安全可靠的连接;第一次握手是由客户端发起,客户端会向服务端发送一个报文,报文里面SYN标志位是置1的,当服务端收到这个报文的时候就知道客户端要和我发起一个新的连接,于是服务端就向客户端发送一个确认消息包ACK位置1,以上两次握手之后,对于客户端而言,其实是已经知道了所有信息,就是我既能给服务端发送消息,我还能收到服务端的消息;对于服务端而言,两次握手是不够的,因为到目前为止,服务端只知道一件事情,客户端给我发送的消息我收的到,但是我发给客户端的消息,客户端能不能收到我还不知道。
所以还要进行第三次握手。第三次握手就是当客户端收到服务端发过来的确认消息的报文之后,还要继续给服务端进行一个回应,也是一个ACK位置1的一个确认消息。
通过以上三次连接,不管是服务端还是客户端都彼此知道了,我既能给对方发送消息也能收到对方的消息,那么这个连接就能被安全的建立了。
第一次SYN,不能携带数据
第二次SYN + ACK携带数据(因为前两次不能确认连接一定是成功的,如果在这个阶段携带数据,会提升发送成本,但有可能失败,所以协议设计时,禁止了携带数据)
第三次ACK,可以携带数据,但不强制
四次握手
涉及到TCP断开连接的操作
示意图
关于四次握手的流程梳理
由客户端首先发起一个结束报文,报文里FIN标志置为1。
当服务器收到报文时,确认要断开连接。但是数据不一定全部发送完毕,因此先进行消息确认,给客户端发起一个报文,报文里ACK置为1。
当服务器准备好了以后,向客户端发送一个FIN置为1的结束报文,表示已经做好准备了。
客户端收到报文后,发送一个确认消息的报文给服务器,服务器直接关闭
客户端等待一段时间后也关闭
关于两个等待时间的分析
CLOSE_WAIT:就是被动方的缓冲时间,将未发送完的数据发送,确保做好了关闭的准备。
Time_WAIT:
1.确认被动关闭方能够顺利进入CLOSED状态。因为如果被动方没有接到报文,就要再次重发,如果直接关闭,就是不负责任、
2.防止失效请求。防止已失效连接的请求数据包与正常连接混淆。就是留时间来接收被动方的请求。
几个问题
Q:如果服务器上出现了大量的CLOSE_WAIT状态的TCP连接,请问这种现象是否合理?
A:单纯从现象上看,无法断定是否合理。因为如果程序设计的时候,会出现较长时间的单方面关闭的情况时,出现大量的CLOSE_WAIT是合理现象但如果程序没有这么设计,那么就是不合理,可能的原因是被动挥手方忘记调用socket.close()
所致。
Q: 服务器上发现了大量的TIME_WAIT状态的TCP连接,是否合理?并说明理由
A:理论上来说,确实是合理的,从标准上来说,没有任何问题,代码正常地关闭了连接,但从实践的角度来看,是不合理的,因为维护连接是有成本的(最主要的硬件成本是内存),客户端和服务器之间的压力是不同的,客户端身上背负的连接比较少(几百条),服务器身上背负的连接很多(几十万 - 几百万)所以,如果让服务器背负这个TIME_WAIT连接的成本,相对压力较大,所以一般建议让客户端来背负这个成本
Q:TCP如何保证数据的有序性?
A:通过序列号保证了数据的有序,发送端主机每次发送数据的时候,会带上SN,而对于接收端来说,它需要通过SN对发送来的数据进行确认,只有当接收端收到了连续的序号的数据时,才会将数据上交给应用层,否则它不会上交给应用层,比如发送0-1000,1000-2000,2000-3000的数据,中间的1000-2000丢包了,那么接收方最多只把0-1000上传给应用层,而不会把后面的数据上传给应用层,并且由于快速重传机制,会一直发送1001告诉发送方这部分数据没收到,当接收方收到这个数据之后,就对这些数据重新排序,所以就保证了数据的有序性。
流量控制
示意图
左侧是根据ASN变化的,右侧是根据ASN+Window变化的。
拥塞控制
发送者根据网络的承载能力控制发送量
该算法根据丢包率作为重要的因素来推算,丢包率 = 单位时间内,没有收到应答的占比,或者说TCP重发的次数占比
慢开始,快启动算法(具体原理:慢启动)
横坐标:时间
纵坐标:当前计算出来的拥塞窗口
慢开始:cwnd的初始值非常小,为1
指数增长转变为线性增长的中间阈值:ssthresh
指数增长:cwnd = cwnd * C(常数,下图中取2)
线性增长:cwnd = cwnd + C(常数,下图中取1)
快启动:指数增长速率快于线性增长
当丢包率大于某个阈值时,就相当于网络拥塞,就通过乘法算法来优化。
发送最大流量(发送窗口) = f ( 拥塞窗口 , 接收窗口 )
**参考文献