1.OSI
OSI 网络协议七层协议 OSI参考模型 描述了概念,OSI参考模型不是一个标准 OSI的实现:TCP/IP
TCP/IP网络数据处理的流程:
先自上而下,后自下而上处理数据头部。
2.TCP是什么
TCP 和UDP都会有源端口和目的端口,端口的这些东西是属于传输层的知识范畴,两个进程在计算机内部进行通信(管道、内存共享、消息队列等方法进行通信)
一台计算机内进程的唯一标识 PID (PID只在本地唯一) socket IP层的IP地址可以唯一标识主机 TCP协议中的端口号可以标识主机中的一个进程。 IP地址+协议+端口号 唯一标识 去标识网络中的一个进程,也成为套接字socket (网络中不同主机上的应用进程之间进行双向通信的端点的抽象)
2.1 传输控制协议TCP简介
TCP是Transmission Control Protocol(传输控制协议) 的简称,它提供一种面向连接的、可靠的、基于字节流的传输层通信协议。 在学习 TCP 握手过程之前,我们首先要了解 TCP 报文头部的一些标志信息,因为在 TCP 握手的过程中,要用到TCP报文头部的一些信息。
2.2 TCP头部
2.2.1 源端口和目的端口
对于端口,我们可以这么理解:我们可以想象发送方很多的窗户,接收方也有很多的窗户,这些窗口都标有不同的端口号,源端口号和目的端口号就分别代表从哪个规定的串口发送到对方接收的窗口。不同的应用程序都有着不同的端口,比如HTTP端口80,SMTP端口25等。
2.2.2 序号 Sequence Number
TCP是面向字节流的,在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。接收端根据这个编号进行确认,保证分割的数据段在原始数据包的位置。
通俗一点的讲,每个字段在传送中用序列号来标记自己位置的,而这个字段就是用来完成双方传输中确保字段原始位置是按照传输顺序的。(发送方是数据是怎样一个顺序,到了接受方也要确保是这个顺序) 引用:https://blog.csdn.net/jdsjlzx/article/details/123980560
2.2.3 确认号 Acknowledgement Number
确认号是期望收到对方下一个报文段的第一个字节的序号 。确认号 = N,则表示到序号N-1为止的所有数据都已经正确收到。例如:B正确收到了A发送过来的一个报文段,其序号字段值为500,而数据字段长度是200字节(序号501~700),这表明B正确收到了A发送的到序号700为止的数据,因此B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701。
2.2.4 数据偏移 offset
头部有可选字段,长度不固定。指出tcp报文段的数据起始处距离tcp报文段的起始有多远,这个字段实际指出Ttcp报文段的首部长度
2.2.5 保留 Reserved
2.2.6 标志位 TCP flags
TCP首部中有 6 个标志比特,它们中的多个可同时被设置为 1,主要是用于操控 TCP 的状态机的,依次为URG,ACK,PSH,RST,SYN,FIN。今天我们只介绍我们用到的三个。
2.2.6.1URG 紧急指针标志
当URG = 1时,表示TCP包的紧急指针域有效,告诉系统这个报文段中有紧急数据,应当尽快传输。 当URG = 0时,忽略紧急指针
2.2.6.2 推送PSH
这个标志位表示Push操作,接收方tcp收到PSH = 1的报文段,就尽快交付给接收接收应用进程而不是再等到这个缓冲区都填满之后再向上交付。
2.2.6.3 复位RST
表示连接复位请求,当RST = 1,标明tcp有严重的错误,必须释放连接,重新建立运输连接。RST = 1还可以用来拒绝一个非法的报文段或者拒绝打开一个连接。
2.2.6.4 确认ACK
这个标志位可以理解为发送端发送数据到接收端,发送的时候 ACK置 为 0,一旦接收端接收数据之后,就将 ACK 置为 1,发送端接收到之后,就知道 了接收端已经接收了数据。需要注意的一点是:当且仅当ACK = 1时,确认号字段才有效。TCP规定,在连接建立后,所有传送的报文段 都将ACK置为1。
2.2.6.5 同步SYN
表示同步序号,用来建立连接,SYN标志位和ACK标志位搭配使用,当连接请求的时候,SYN=1,ACK=0;连接被响应的时候,SYN=1,ACK=1;这个标志的数据包经常被用来进行端口扫描。扫描者发送一个只有SYN的数据包,如果对方主机响应了一个数据包回来 ,就表明这台主机存在这个端口;但是由于这种扫描方式只是进行TCP三次握手的第一次握手,因此这种扫描的成功表示被扫描的机器不很安全,一台安全的主机将会强制要求一个连接严格的进行TCP的三次握手。
2.2.6.6 终止FIN
当发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送方FIN标志位置为1后,表示此报文段的发送方数据发送完毕,请求释放连接。
2.2.7 window 窗口
滑动窗口大小 ,用来告知 发送端 接收端的缓存大小 以此控制发送端的发送数据速率 达到流量控制
2.2.8 检验和
目的是为了发现TCP首部和数据在发送端到接收端之间发生的任何改动。如果接收方检测到检验和有差错,则TCP段会被直接丢弃。
2.2.9 紧急指针
TCP flags 中的URG 为1时,才有效
3. TCP三次握手过程
TCP 三次握手的过程解决以下三个问题
- 要是每一方都能确知对方的存在
- 要允许双方协商一些参数(如窗口最大值,是否使用窗口扩大选项以及时间戳选项等)
- 能够对运输实体资源(如缓冲大小、连接表中的项目等)进行分配
掌握了这些,TCP 的三次握手就简单多了。下面我们就以动画形式进行拆解三次握手过程。 图 2-1
初始状态:客户端处于closed(关闭)状态,服务器处于listen(监听)状态 有地方说也处于关闭状态
第一次握手:建立连接时,客户端发送SYN包[syn=x ] 到服务器,并进入SYN_Send状态 ,等待服务器确认。
报文 SYN = 1 同步序列号和初始化序列号seq = x发送给服务端 。
第二次握手:服务端受到SYN请求报文之后,如果同意连接,会以自己的同步序列号SYN(服务端) = 1、初始化序列号seq = y和确认序列号(期望下次收到的数据包)ack = x+ 1以及确认号ACK = 1报文作为应答,
服务器为SYN_Receive状态。 第三次握手: 客户端接收到服务端的SYN + ACK之后,知道可以下次可以发送了下一序列的数据包了,然后发送同步序列号ack = y + 1和数据包的序列号seq = x + 1以及确认号ACK = 1确认包作为应答,客户端转为established状态。
4. 为什么不能是一次、二次握手,而必须是三次握手
4.1 为了初始化Sequence Number的初始值
通讯的双方要 互相通知对方 自己的初始化sequence number值,即图2-2 的x 、y值 ,这个值要做为以后的数据通信序号, 保证应用层接收到的数据不会因为网络上的传输问题而乱序,即TCP 会用这个序号来拼接数据。 因此在服务器回发它的sequence number ,即第二次握手之后还需要发送确认报文给服务器,告知服务器客户端已经收到你的初始化sequence number。 4.2 SYN 超时的问题
此外在第一次握手 有个隐患,SYN 超时的问题:
- 如果Server 收到 Client 的 SYN,回复SYN-ACK的时候未收到ACK确认。
(第一次握手,client 给server SYN 就掉线了 ,server 给client 端发送的SYN-ACK client 收不到,server端没有收到client端的ACK确认 ,那么这个连接就会处于一个中间状态 既没有失败也没有失败) - server不断重试直至超时时,liunx默认等待63秒才断开连接
(server端如果没有收到client 的回执,那么server会重发SYN-ACK,在Linux下会重试5次 ,从一秒开始 每次都翻倍 5次的间隔时间为1秒 2秒 4秒 8秒 16秒 总共31秒 再等待32秒后 才能判定超时, 等于说server等待63秒后TCP才会断开连接)
SYN超时造成的后果:服务器可能遭到SYN-Flood的攻击风险 ,恶意程序会给服务发送一个SYN文,然后就下线了 然后服务要默认等待63秒 才会断开这个连接 。这样攻击者就会把服务器的连接队列耗尽,让正常的连接请求不能处理。
SYN-Flood:服务器创建多个半连接由此来使得服务器的资源被消耗殆尽。
SYN-Flood防护措施
- SYN队列满了后,通过tcp_syncookies 参数回发 SYN Cookie。
当syn队列满了的时候,tcp会通过原地址端口、目标地址端口 和时间戳 打造一个特别的synchronize number 回发回去 synchronize number 简称 syncookie,如果是攻击者他是不会有响应的。 - 若为正常连接则client会回发SYN Cookie, 直接建立连接
如果是正常连接 只会把syncookie 发回来,然后服务端可以通过syncookie 建立连接,通过syncookie 即便此时SYN队列满了,本次连接请求不在队列中,依然能够建立连接
如果建立连接,client出现故障怎么办 保活机制 (tcp 设有保活机制)
- 向对方发送保活探测报文,如果未收到响应则继续发送
- 尝试次数达到保活探测数仍然未收到响应则中断连接。
在一段时间(称为保活时间)Keep-alive Time, 在这段时间 连接处于非活动状态, 开启保活功能的一端将向对方发送一个保活探测报文,如果发送端没有收到响应报文,那么经过已经提前配置好的保活时间间隔Keep-alive Time , 将继续发送保活探测报文,直到探测次数达到保活探测数,对方主机被确认未不可达 连接也被终断。
5. 四次挥手
“挥手”是为了终止连接,四次挥手的流程图如下: 断开一个TCP连接时,需要客户端和服务端总共发出4个包以确定连接的断开,在socket 由客户端或服务端任意一方执行close来触发,我们假设由客户端主动触发close。
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
第一次挥手:客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送客户端进入FIN_WAIT_1状态。 第二次挥手:服务器B收到这个FIN,它发回一个ACK给客户端,确认序号为收到的序号加1和SYN一样,一个FIN将占用一个序号。server 进入CLOSE_WAIT状态 第三次挥手:服务器B发送一个FIN给客户端A,用来关闭与客户端A的连接 ,server 进入LAST_ACK状态。 第四次挥手:客户端A收到FIN后,客户端进入到TIME_WAIT状态,接着发送一个ACK给服务端server ,确认序号为收到序号+1 ,服务端进入CLOSED状态,完成四次握手。
参考文章: TCP三次握手四次挥手详解 https://zhuanlan.zhihu.com/p/40013850#
|