相对于SOCKET开发者,TCP创建过程和链接折除过程是由TCP/IP协议栈自动创建的.因此开发者并不需要控制这个过程.但是对于理解TCP底层运作机制,相当有帮助.
因此在这里详细解释一下这两个过程。
讲解前先介绍下tcp头部:
TCP三次握手
所谓三次握手(Three-way Handshake),是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。
三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换 TCP 窗口大小信息.在socket编程中,客户端执行connect()时。将触发三次握手。
- 第一次握手:
客户端发送一个TCP的SYN标志位置1的包指明客户打算连接的服务器的端口,以及初始序号X,保存在包头的序列号(Sequence Number)字段里。客户端状态变为SYN_SENT - 第二次握手:
服务器发回确认包(ACK)应答。即SYN标志位和ACK标志位均为1同时,将确认序号(Acknowledgement Number)设置为客户的I S N加1以.即X+1。服务器状态变为SYN_RCVD - 第三次握手.
客户端再次发送确认包(ACK) SYN标志位为0,ACK标志位为1.并且把服务器发来ACK的序号字段+1,放在确定字段中发送给对方.并且在数据段放写ISN的+1。客户端和服务器状态变为ESTABLISHED
SYN攻击
在三次握手过程中,服务器发送SYN-ACK之后,收到客户端的ACK之前的TCP连接称为半连接(half-open connect).此时服务器处于Syn_RECV状态.当收到ACK后,服务器转入ESTABLISHED状态.
Syn攻击就是 攻击客户端 在短时间内伪造大量不存在的IP地址,向服务器不断地发送syn包,服务器回复确认包,并等待客户的确认,由于源地址是不存在的,服务器需要不断的重发直 至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,目标系统运行缓慢,严重者引起网络堵塞甚至系统瘫痪。
Syn攻击是一个典型的DDOS攻击。检测SYN攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击.在Linux下可以如下命令检测是否被Syn攻击
netstat -n -p TCP | grep SYN_RECV
一般较新的TCP/IP协议栈都对这一过程进行修正来防范Syn攻击,修改tcp协议实现。主要方法有SynAttackProtect保护机制、SYN cookies技术、增加最大半连接和缩短超时时间等.
但是不能完全防范syn攻击。
SYN-ACK 重传次数 服务器发送完SYN+ACK包,如果未收到客户确认包,服务器进行首次重传(重传次数受限 net.ipv4.tcp_synack_retries ,默认为5,表示重发5次),等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超 过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。注意,每次重传等待的时间不一定相同。
查看SYN queue 溢出 netstat -s | grep LISTEN 102324 SYNs to LISTEN sockets dropped
查看Accept queue 溢出 netstat -s | grep TCPBacklogDrop TCPBacklogDrop: 2334
半连接存活时间:是指半连接队列的条目存活的最长时间,也即服务从收到SYN包到确认这个报文无效的最长时间,该时间值是所有重传请求包的最长等待时间总和。有时我们也称半连接存活时间为Timeout时间、SYN_RECV存活时间。
连接队列参数:
SYN queue 队列长度由 /proc/sys/net/ipv4/tcp_max_syn_backlog 指定,默认为2048。
Accept queue 队列长度由 /proc/sys/net/core/somaxconn 和使用listen函数时传入的参数,二者取最小值。默认为128
TCP 四次挥手
TCP的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake)。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作即可产生挥手操作。
- 客户端先向服务器发送FIN报文,请求断开连接,其状态变为FIN_WAIT1。
- 服务器收到FIN后向客户端发送ACK,服务器的状态围边CLOSE_WAIT。
- 客户端收到ACK后就进入FIN_WAIT2状态,此时连接已经断开了一半了。如果服务器还有数据要发送给客户端,就会继续发送;直到发完数据,就会发送FIN报文,此时服务器进入LAST_ACK状态。
- 客户端收到服务器的FIN后,马上发送ACK给服务器,此时客户端进入TIME_WAIT状态;再过了2MSL长的时间后进入CLOSED状态。服务器收到客户端的ACK就进入CLOSED状态。
CLOSING状态表示:
客户端发送了FIN,但是没有收到服务器的ACK,却收到了服务器的FIN,这种情况发生在服务器发送的ACK丢包的时候,因为网络传输有时会有意外。
测试
测试一:
拔掉客户端网线,客户端会尝试重发(间隔由短“”几毫秒“”到长“”几秒甚至更长“”),服务端仍不知道客户端断开的状态,插上网线后连接继续维持(windows telnet,linux回显服务)
测试二:
kill客户端或kill服务端,都会触发四次挥手
测试三:
拔掉服务端网线,客户端也收不到服务端的状态
因此维持逻辑心跳是有必要的;