tcp协议问题小结
一、TCP三次握手和四次挥手
1、建立连接的时候的三次握手过程
下面解释一下图中的各个状态的含义:
①LISTEN: 表示Server端的某个 SOCKET 处于监听状态,可以接受连接了。
②SYN_SENT: 当客户端 SOCKET 执行 CONNECT 连接时,它首先发送 SYN 报文,因此也随即它会进入到了 SYN_SENT 状态,并等待服务端发送三次握手中的第 2 个报文。SYN_SENT 状态表示客户端已发送 SYN 报文。
③SYN_RCVD: 这个状态表示Server端接收到了 SYN 报文,在正常情况下,这个状态是服务器端的 SOCKET 在建立 TCP 连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用 netstat 你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP 握手过程中最后一个 ACK 报文不予发送。因此这种状态时,当收到客户端的 ACK 报文后,它会进入到 ESTABLISHED 状态。
④ESTABLISHED:表示连接已经建立了。
2、关闭连接的时候的四次挥手过程如下所示
其中几个主要的状态含义解释如下:
①FIN_WAIT_1:FIN_WAIT_1和FIN_WAIT_2两个状态都表示等待对方的FIN报文。只不过一般FIN_WAIT_1实际上是Client端在ESTABLISHED状态的时候,想要主动关闭连接的话就需要主动向Server端发送FIN报文请求关闭连接,然后进入FIN_WAIT_1状态,这个状态持续时间短暂(因为在实际情况下,Server收到Client的FIN之后都会马上发送一个ACK,FIN_WAIT_1这种状态一般很少看到),然后收到Server发送的ACK之后进入FIN_WAIT_2状态
②FIN_WAIT_2:上面也说道这种状态以及和FIN_WAIT_1的区别,另外注意的是对于Client而言,已经收到了Server的ACK,Server端将要关闭连接但是Client端还需要发送给Server一个ACK,需要等会再关闭连接(所以这种状态也成为半连接)
③CLOSING : 表示双方同时关闭连接。这种情况比较特殊,考虑一下这种情况,双方同时调用close()函数,然后同时发送FIN报文。正常情况下应该是一方发送FIN报文然后先接受到ACK在接收到FIN报文(或者同时接收到FIN和ACK),但是如果双方几乎在同时 close 一个 SOCKET 的话,那么就出现了双方同时发送 FIN 报文的情况 , 也即会出现 CLOSING 状态 , 表示双方都正在关闭 闭 SOCKET 连接,就会出现这种状态
④CLOSE_WAIT:表示Server正在等待连接的关闭,这时候需要向对方发送一个接收到FIN的ACK报文(收到Client发送的FIN之后),接下来,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以关闭这个连接,发送 FIN 报文给对方,也即关闭连接。所以你在 CLOSE_WAIT 状态下,需要完成的事情是等待自己这一方去关闭连接。
⑤LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送 FIN 报文后,最后等待对方的 ACK 报文。当收到 ACK 报文后,也即可以进入到 CLOSED 可用状态了。
⑥CLOSED: 表示连接中断。
3、总结一下
①首先 Client 端发送连接请求报文,Server 接受连接后回复 ACK 报文,并为这次连接分配资源。Client 端接收到 ACK 报文后也向 Server 段发生 ACK 报文,并分配资源,这样TCP 连接就建立了。ACK 是TCP 报头的控制位之一(一个字节),对数据进行确认。确认由目的端发出,用它来告诉发送端这个序列号之前的数据段都收到了.比如,确认号为 X,则表示前 X-1 个数据段都收到了,只有当ACK=1时,确认号才有效,当ACK=0时,确认号无效,这时会要求重传数据,保证数据的完整性.SYN 同步序列号,TCP 建立连接时将这个位置 1。FIN 发送端完成发送任务位,当 TCP 完成数据传输需要断开时,提出断开连接的一方将这位置 1。【注意】中断连接端可以是 Client 端,也可以是 Server
②假设Client端发起关闭连接的请求(FIN),Server收到FIN之后得到的消息就是Client端没有数据要发送给自己了,但是不代表Server端的所有数据都已经发送完毕,这个时候就不能着急关闭连接,如果还有要发送的数据就继续发送,所以这个时候就发送一个确认收到FIN的ACK报文表示自己接收到了Client端想要关闭连接的请求,并发送剩余数据。这个时候Client就进入FIN_WAIT_2的状态等待Server继续发送数据和Server的FIN报文。当Client收到Server发送的FIN报文之后(表示Server已经发送完剩余的数据了),知道可以关闭连接了,要给Server端发送确认关闭连接的ACK报文,当Server收到ACK之后就可以断开连接了。如果其中Client等待2MSL没有收到,说明Server已经关闭就会关闭Client自己的连接。(RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等)
③在 TIME_WAIT 状态中,如果 TCP client 端最后一次发送的 ACK 丢失了,它将重新发送。TIME_WAIT 状态中所需要的时间是依赖于实现方法的。典型的值为 30 秒、1分钟和 2 分钟。等待之后连接正式关闭,并且 所有的资源( 包括端口号)
④归结一下Server和Client的整个状态图
Client的状态转换
Server的状态转换
二、TCP连接建立和释放的其他典型问题
1、为什么收到 Server 端的确认之后,tClient 还需要进行第三次 “ 握手 ” 呢?
①采用三次握手是为了防止失效的连接请求报文段突然又传送到Server ,因而产生错误。
②“已失效的连接请求报文段”的产生在这样一种情况下:client 发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了(因为网络并发量很大在某结点被阻塞了),以致延误到连接释放以后的某个时间才到达 server。 本来这是一个早已失效的报文段。但 server 收到此失效的连接请求报文段后 ,就误认为是 client 再次发出的一个新的连接请求。于是就向 client 发出确认报文段,同意建立连接。假设不采用“ 三次握手” ,那么只要 server 发出确认 , 新的连接就建立了 。 由于现在 client 并没有发出建立连接的请求 , 因此不会理睬 server 的确认 , 也不会向 server 发送数据 。但 server 却以为新的运输连接已经建立,并一直等待 client 发来数据。这样,server 的很多资源就白白浪费掉了 。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client 不会向 server 的确认发出确认。server 由于收不到确认,就知道 client 并没有要求建立连接。 主要目的防止 server 一直处于等待状态浪费资源。
③看下面的例子
在上一个TCP连接中,A向B发送的连接请求SYN报文段在由于网络阻塞或者其他原因停留在网络中某处,于是A超时重传,与B建立了TCP连接,交换了数据,最后也关闭了接。但是由于滞留在网络中的陈旧的SYN报文段现在传送到了B了,如果不使用3次握手,B就会以为A现在正在请求建立连接,就会分配资源准备连接。但是实际上这个SYN只是上一次A9发送的失效的SYN,并没有想要建立连接,也不会与B交换数据,这就白白浪费了资源。
如果使用3次握手,那么B在接收到A的陈旧的SYN报文之后,就会向A发送确认的SYN报文并选择一个序号seq=y,同时发送一个序号为x+1的ACK,A接收到这样的报文之后就会从确认号得出自己并没有发送这样的连接请求(这是滞留在网络中的失效SYN报文),这个时候A就会发送复位报文段,在这个报文段中RST=1、ACK=1、确认号ack=y+1表示收到了B的SYN和ACK但是表示自己并没有想要建立连接(RST=1),B收到这样的报文从RST就不会建立连接。
总之,如果两次握手的话,客户端有可能因为网络阻塞等原因会发送多个请求报文,这时服务器就会建立连接,浪费掉许多服务器的资源。
2、为什么要四次挥手
确保数据能够完成传输。但关闭连接时,当Server收到Client的 FIN 报文通知时,它仅仅表示Client没有数据发送了;但未必表示Server的所有的数据都全部发送给对方了,所以未必会马上会关闭 SOCKET,也即Server可能还需要发送一些数据给对方之后,再发送 FIN 报文给对方来表示你同意现在可以关闭连接了,所以它这里的 ACK 报文和 FIN 报文多数情况下都是分开发送的。
TCP 协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP 是 全双工模式,这就意味着,当Client 发出 FIN 报文段时,只是表示Client已经没有数据要发送了,Client 告诉Server,它的数据已经全部发送完毕了,请求关闭连接;但是,这个时候Client 还是可以接受来自Server的数据;当Server返回 ACK 报文段时,表示它已经知道Client没有数据发送了,但是Server还是可以发送数据到Client的;当Server也发送了 FIN 报文段时,这个时候就表示Server也没有数据要发送了,就会告诉Client,我也没有数据要发送了,之后彼此就会愉快的中断这次 TCP 连接。
3、建立连接的第二个 syn 作用是啥
因为客户端发送的 syn 可能过了好久才到达服务端,而此时客户端超时重传的 SYN 已经到达服务端,那么后来的 SYN 就是无效的,如果不发第二个 syn 查询客户端是否有效的话,服务端就会监听这个延迟到达的请求,造成资源的浪费。所以可以强制发送一个 SYN询问客户端之前的请求是否有效。
4、time_wait 状态产生 的 原因?
①可靠地实现 TCP 全双工连接的终止。我们必须要假想网络是不可靠的,无法保证最后发送的 ACK 报文会一定被对方收到,因此对方处于 LAST_ACK 状态下的 SOCKET 可能会因为 超时未收到 ACK 报文,而重发 FIN报文,client 必须维护这条连接的状态 ( 保持 time_wait ,具体而言 ,就是这条 TCP 连接对应的 ( local_ip, local_port ) 资源不能被立即释放或重新分配 ) 以便 可以重发 丢失 的ACK ,如果主动关闭端不维持 TIME_WAIT 状态,而是处于 CLOSED 状态,主动关闭端将会响应一个 RST,结果 server 认为发生错误,导致服务器端不能正常关闭连接。所以这个TIME_WAIT 状态的作用就是用来重发可能丢失的 ACK 报文。所以,当客户端等待 2MSL(2倍报文最大生存时间)后,没有收到服务端的 FIN 报文后,他就知道服务端已收到了 ACK报文,所以客户端此时才关闭自己的连接。
②允许老的重复分节在网络中消逝。如果 TIME_WAIT 状态保持时间不足够长 ( 比如小于 2MSL) ,第一个连接就正常终止了。 第二个拥有相同四元组(local_ip, local_port,remote_ip,remote_port)的连接出现(建立起一个相同的 IP 地址和端口之间的 TCP 连接),而第一个连接的重复报文到达,干扰了第二个连接。 TCP 实现 必须防止某个连接的重复报文在连接终止后出现,所以让TIME_WAIT 状态保持时间足够长 (2MSL) ,连接相应方向上的 TCP 报文要么完全响应完毕,要么被丢弃。建立第二个连接的时候,不会混淆。
5、如果网络连接中出现大量 TIME_WAIT 带来的危害
如果系统中有很多 socket 处于 TIME_WAIT 状态,当需要创建新的 socket 连接的时候可能会受到影响,这也会影响到系统的扩展性。之所以 TIME_WAIT 能够影响系统的扩展性是因为在一个 TCP 连接中,一个 Socket 如果关闭的话,它将 保持 TIME_WAIT 约 状态大约 1-4 钟 分钟 。如果很多连接快速的打开和关闭的话,系统中处于 TIME_WAIT 状态的socket 将会积累很多,由于 本地端口数量的限制,同一时间只有有限数量的 socket 连接可以建立, 如果太多的 socket 处于 TIME_WAIT 状态,你会发现,由于用于新建连接的本地端口太缺乏,将会很难再建立新的对外连接。
6、TCP 如 何 保 证 可 靠 传 输 ?
0、在传递数据之前,会有三次握手来建立连接。
1、应用数据被分割成 TCP 认为最适合发送的数据块(按字节编号,合理分片)。这和 UDP完全不同,应用程序产生的数据报长度将保持不变。 ( 将数据截断为合理的长度)
2、当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。( 超时重发)
3、当 TCP 收到发自 TCP 连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒 。( 对于收到的请求,给出确认响应) (之所以推迟,可能是要对包做完整校验)。
4、TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到
此报文段。 ( 校验出包有错,丢弃报文段,不给出响应,TCP 发送数据端,超时时会重发数据)
5、既然 TCP 报文段作为 IP 数据报来传输,而 IP 数据报的到达可能会失序,因此 TCP 报文段的到达也可能会失序。如果必要,TCP 将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。 ( 对失序数据进行重新排序,然后才交给应用层)
6、既然 IP 数据报会发生重复,TCP 的接收端必须丢弃重复的数据。( 对于重复数据 , 能够丢弃重复数据)
7、TCP 还能提供流量控制。TCP 连接的每一方都有固定大小的缓冲空间。TCP 的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲
区溢出。(TCP 可以进行流量控制,防止较快主机致使较慢主机的缓冲区溢出)TCP 使用的流量控制协议是可变大小的滑动窗口协议。
8、TCP 还能提供拥塞控制。当网络拥塞时,减少数据的发送。
7、TCP 三次握手有哪些漏洞 ?
1.SYN Flood 攻击
SYN Flood 是 DDoS 攻击的方式之一,这是一种利用 TCP 协议缺陷,发送大量伪造的 TCP 连接请求,从而使得被攻击方资源耗尽(CPU 满负荷或内存不足)的攻击方式。
要明白这种攻击的基本原理,还是要从 TCP 连接建立的过程开始说起:
首先,请求端(客户端)发送一个包含 SYN 标志的 TCP 报文,SYN 即同步(Synchronize),同步报文会指明客户端使用的端口以及 TCP 连接的初始序号;第二步,服务器在收到客户端的 SYN 报文后,将返回一个 SYN+ACK 的报文,表示客户端的请求被接受,同时 TCP 序号被加一,ACK 即确认(Acknowledgment)。第三步,客户端也返回一个确认报文 ACK 给服务器端,同样 TCP 序列号被加一,到此一个 TCP 连接完成。
以上的连接过程在 TCP 协议中被称为三次握手。问题就出在 TCP 连接的三次握手中,假设一个用户向服务器发送了 SYN 报文后突然死机或掉线,那么服务器在发出SYN+ACK应答报文后是无法收到客户端的ACK报文的(第三次握手无法完成), 这种情况下服务器端一般会 不停地 重试 ( 再次发送 SYN+ACK 给客户端 ) 并等待一段时间后丢弃这个未完成的连接,这段时间的长度我们称为 SYN Timeout(大约为 30 秒-2 分钟);一个用户出现异常导致服务器的一个线程等待 1 分钟并不是什么很大的问题,但如果有一个恶意的攻击者 发送大量 伪造原 IP 地址 的攻击报文,发送到服务端, 服务器端将为了维护一个非常大的 半连接 队列 而消耗非常多的 CPU 时间和内存。。服务器端也将忙于处理攻击者伪造的 TCP 连接请求而无暇理睬客户的正常请求(毕竟客户端的正常请求比率非常之小),此时从正常客户的角度看来,服务器失去响应,这种情况我们称作:服务器端受到了 SYN Flood 攻击(SYN 洪水攻击)。
原理:攻击者首先伪造地址对 服务器发起 SYN 请求,服务器回应(SYN+ACK)包,而真实的 IP 会认为,我没有发送请求,不作回应。服务 器没有收到回应,这样的话,服务器不知 道(SYN+ACK)是否发送成功,默认情况下会重试 5 次(tcp_syn_retries)。这样的话,对于服务器的内存,带宽都有很大的消耗。攻击者 如果处于公网,可以伪造 IP 的话,对于服务器就很难根据 IP 来判断攻击者,给防护带来很大的困难。
8、几种拥塞控制方法
慢开始 和 拥塞避免、 快重传和快恢复。
①慢开始和拥塞避免算法的实现举例
②连续收到3个冗余ACK转入拥塞避免阶段