1.三次握手(TCP建立连接过程)
- 第一次握手:起初两端都处于CLOSED关闭状态,Client将标志位SYN=1,随机产生一个值seq=x,并将该数据包发送给Server,Client进入SYN-SENT状态,等待Server确认;
- 第二次握手:服务器收到数据包后由标志位SYN=1得知Client请求建立连接,服务器将标志位SYN和ACK都置为1,ack=x+1,随机产生一个值seq=y,并将该数据包发送给Client以确认连接请求,服务器进入SYN-RCVD状态,此时操作系统为该TCP连接分配TCP缓存和变量;
- 第三次握手:客户端收到确认后,检查ack=x+1,ACK=1,如果正确则将标志位ACK置为1,ack=y+1,并且此时操作系统为该TCP连接分配TCP缓存和变量,并将该数据包发送给服务器,服务器检查ack=y+1,ACK=1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手。
其中:SYN 表示建立连接,为同步序列编号,是TCP/IP建立连接时使用的握手信号
ACK 表示响应,是确认字符,在数据通信中,接收站发给发送站的一种传输类控制字符。表示发来的数据已确认接收无误。在TCP/IP协议中,如果接收方成功的接收到数据,那么会回复一个ACK数据。
相关问题
-
为什么客户端还要发送一次确认呢?可以二次握手吗?
主要为了防止已失效的连接请求报文段突然又传送到了服务端。
如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。第二次建立了连接。数据传输完毕后,就释放了连接;但客户端发送的第一个丢失的报文可能只是在某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认,就建立新的连接了,此时客户端不理睬服务端的确认且不发送数据,则服务端一致等待客户端发送数据,浪费资源。 -
Server端易受到SYN攻击?
服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击,SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。
防范SYN攻击措施:降低主机的等待时间使主机尽快的释放半连接的占用,短时间受到某IP的重复SYN则丢弃后续请求。
2.四次挥手(TCP关闭连接过程)
- 第一次挥手:客户端的应用进程先向其TCP发出关闭连接报文(FIN=1,序号seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN-WAIT-1(终止等待1)状态,等待B的确认。
- 第二次挥手:服务器收到连接释放报文段后,由于服务器还没有完成数据发送,所以给客户端一个响应(ACK=1,确认号ack=u+1,序号seq=v)说我接收到了你的关闭连接报文,但我还没准备好,服务器进入CLOSE-WAIT(关闭等待)状态,此时的TCP处于半关闭状态,客户端收到服务器的确认后,进入FIN-WAIT-2(终止等待2)状态,等待服务器发出的连接释放报文段。
- 第三次挥手:服务器完成数据发送,想客户端发出连接释放报文段(FIN=1,ACK=1,序号seq=w,确认号ack=u+1),服务端进入LAST-ACK(最后确认)状态,等待客户端的确认。
- 第四次挥手:客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),客户端进入TIME-WAIT(时间等待2ms)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,仍未收到服务端的接收响应,说明服务端已经关闭连接,则客户端也进入CLOSED状态。
其中:FIN表示关闭连接
相关问题
-
为什么A在TIME-WAIT状态必须等待2MSL的时间?
MSL最长报文段寿命Maximum Segment Lifetime,MSL=2
1)保证A发送的最后一个ACK报文段能够到达B
这个ACK报文段有可能丢失,使得处于LAST-ACK状态的服务端收不到对已发送的FIN+ACK报文段的确认,服务端超时重传FIN+ACK报文段,而客户端能在2MSL时间内收到这个重传的FIN+ACK报文段,接着客户端重传一次确认,重新启动2MSL计时器,最后客户端和服务端都进入到CLOSED状态,若客户端在TIME-WAIT状态不等待一段时间,而是发送完ACK报文段后立即释放连接,则无法收到B重传的FIN+ACK报文段,所以不会再发送一次确认报文段,则服务端无法正常进入到CLOSED状态。
2)防止“已失效的连接请求报文段”出现在本连接中
。
A在发送完最后一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。 -
为什么连接的时候是三次握手,关闭的时候却是四次握手?
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。 -
为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
网络的可靠性。
由于会出现不可信的假象网络,所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。 -
四次挥手时Time_wait过多
原因:在高并发短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于TIME_WAIT状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上
。
解决:
编辑内核文件/etc/sysctl.conf,加入以下内容:
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME- WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout 修改系默认的 TIMEOUT 时间
然后执行 sysctl -p 让参数生效.
/etc/sysctl.conf
是一个允许改变正在运行中的Linux系统的接口,它包含一些TCP/IP堆栈和虚拟内存系统的高级选项,修改内核参数永久生效。
简单来说,就是打开系统的TIMEWAIT重用和快速回收
。
- Close_wait过多
- 程序问题:如果代码层面忘记了 close 相应的 socket 连接,那么自然不会发出 FIN 包,从而导致 CLOSE_WAIT 累积;或者代码不严谨,出现死循环之类的问题,导致即便后面写了 close 也永远执行不到。
- 响应太慢或者超时设置过小:如果连接双方不和谐,一方不耐烦直接 timeout,另一方却还在忙于耗时逻辑,就会导致 close 被延后。响应太慢是首要问题,不过换个角度看,也可能是 timeout 设置过小。
- BACKLOG 太大:此处的 backlog 不是 syn backlog,而是 accept 的 backlog,如果 backlog 太大的话,设想突然遭遇大访问量的话,即便响应速度不慢,也可能出现来不及消费的情况,导致多余的请求还在队列里就被对方关闭了。