TCP协议
TCP协议是一个面向链接、可靠的字节流服务,被TCP协议封装后的数据我们称为报文。下面是TCP的包头,其大小为20字节。在一个TCP连接中,仅有两方进行彼此通信,广播和多播不能用于TCP。TCP使用校验和,确认和重传机制来保证可靠传输。TCP采用累积确认来提高传输速度。TCP使用滑动窗口机制来实现流量控制,通过动态改变窗口大小进行拥塞控制。
连接的建立和终止
下面是通过tcpdump命令捕获的信息
每条记录的格式为源地址>目的地址:标志位,标志位有以下内容
1415531521:1415531521(0)表示分组编号为1415531521(也是起始字节数),第二个1415531521表示结束字节数,0表示报文中包含的数据大小为0;这个握手的报文,理解起来比较麻烦,看一个简单点的21:32(11),21表示发送的字节编号为21,即前面已经发送了20个字节了,现在从第21个字节开始发送,并将该字节编号作为分组编号来使用,32表示该分组截至字节编号(不包括32),11表示这个分组包含的字节数。
win 4096表示发送端窗口大小,即表示自己的缓冲区还是多少剩余空间
mss 1024表示表示发送端接受的最大报文长度(数据部分,不包含TCP头),超过这个长度将拒绝接受。这是因为数据链路层有个MTU(1500字节),超过这个字节链路层将不会发送。因此,如果TCP报文太大的话就会在IP层进行分片以满足链路层MTU的硬性要求。
连接建立
TCP连接的建立被称作三次握手(Threeway Handshake),是指建立一个 TCP 连接时,需要客户端和服
务器总共发送3个包。三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行connect()时,将触发三次握手。
-
第一次握手(SYN=1, seq=x)
客户端发送一个 TCP 的 SYN 标志位置1的包,指明客户端打算连接的服务器的端口,以及初始序号x,保存在包头32位序列号字段里。发送完毕后,客户端进入 SYN_SEND 状态。
-
第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1)
服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己序列号y,保存在包头32位序列号字段里,同时将包头的32位确认序号设置为客户端序列号 加1,即x+1。 发送完毕后,服务器端进入 SYN_RCVD状态。
-
第三次握手(ACK=1,ACKnum=y+1)
客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来序号y+1,放在确定包头的32位确认序号字段中发送给对方,客户端进入ESTABLISHED状态,当服务器端接收到这个包时,也入ESTABLISHED状态,TCP 握手结束。
三次握手的示意图如下所示:
连接断开
TCP的连接的拆除需要发送四个包,因此称为四次挥手(Fourway handshake),也叫做改进的三次握手。客户端或服务器均可主动发起挥手动作,在 socket 编程中,任何一方执行close()操作即可产生挥手操作。
-
第一次挥手(FIN=1,seq=x)
假设客户端想要关闭连接,客户端发送一个FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。发送完毕后,客户端进入 FIN_WAIT_1 状态。
-
第二次挥手(ACK=1,ACKnum=x+1)
服务器端确认客户端的FIN包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。发送完毕后,服务器端进入CLOSE_WAIT状态,客户端接收到这个确认包之后,进入FIN_WAIT_2状态,等待服务器端关闭连接。
-
第三次挥手(FIN=1,seq=y)
服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN置为1。发送完毕后,服务器端进入LAST_ACK状态,等待来自客户端的最后一个ACK。
-
第四次挥手(ACK=1,ACKnum=y+1)
客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。服务器端接收到这个确认包之后,关闭连接,进入CLOSED状态。客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入CLOSED状态。
四次挥手的示意图如下:
-
握手和挥手具体例子
TCP状态迁移图
图中当应用程序位于TIME_WAIT时需要等待2MSL的时间。这是确保自己发送的ACK对方能收到,如果对发在容忍的时间内没有收到ACK则对发会再次发送FIN。第二个就是清除网络中存在TCP副本。因为TCP的重传机制一定会导致网络中存在TCP副本,但是我们已经将SOCKET关闭了,并不需要这些副本,所以位于TIME _WAIT状态的SOCKET会将姗姗来迟的副本扔掉。
连接被重置
在开发中我们可能遇到这种错误:Connection reset by peer
产生这种原因是对方发送了一个RESET包,即TCP头中的RST字段被置为1。一般下面三种具体情况会这种包。
到一个不存在的端口
我们要连接到一个不存在的端口,则对发会直接发送一个RESET包过来。
异常中止一个链接
正常关闭一个连接是将缓冲区的数据发送完毕并发送FIN,异常关闭是发送方丢弃发送缓冲区中的数据并发送RESET包。需要注意的是对发收到RESET包后终止连接并不发送任何数据。
半打开状态
如果一方已经关闭或异常终止连接而另一方还不知道,我们将这样的连接称为半打开状态。只要在半打开的连接上发送数据,那么发送方会收到RESET包。
拥塞控制
慢启动算法给出了在链路上发送数据包的解决方案,即将滑动窗口更名为拥塞窗口(cwnd),拥塞窗口初始值为1,如果收到对方的ack,则窗口大小变为2,依次类推,窗口的大小始终以2的倍数增长。但是这样会导致网络拥塞。于是又提出了拥塞避免算法。将两种算法结合来控制包的发送。下面是一个算法的示意图。有两个值需要注意拥塞窗口大小cwnd和门限值ssthresh。此外还有快重传算法和快恢复算法来避免网络中的数据出现过载或者低载的状况,这些算法都在RCF2001文档中进行具体的说明。在使用滑动窗口时,会出现糊涂窗口综合症(Silly Window Syndrome),在问题可以通过Nagle算法来解决。
SYN攻击
-
什么是SYN攻击(SYN Flood)
在三次握手过程中,服务器发送SYNACK之后,收到客户端的 ACK之前的TCP连接称为半连接(helf-open connect)。此时服务器处于 SYN_RCVD 状态。当收到 ACK后,服务器才能转入 ESTABLISHED 状态。SYN 攻击指的是,攻击客户端在短时间内伪造大量不存在的IP地址,向服务器不断地发送SYN包,服务器回复确认包,并等待客户的确认。由于源地址是不存在的,服务器需要不断的重发直至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,导致目标系统运行缓慢,严重者会引起网络堵塞甚至系统瘫痪。
-
如何检测 SYN 攻击
检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击。
-
如何防御 SYN 攻击
SYN攻击不能完全被阻止,除非将TCP协议重新设计。我们所做的是尽可能的减轻
SYN攻击的危害,常见的防御 SYN 攻击的方法有如下几种:- 缩短超时(SYN Timeout)时间
- 增加最大半连接数
- 过滤网关防护
- SYN cookies技术
参考博文
http://www.cnblogs.com/danbo/p/4614957.html
http://www.cnblogs.com/Jtianlin/p/4339931.html