其他链接:
以下部分内容参考于:http://www.jianshu.com/p/ef892323e68f
一、TCP是什么
TCP
,Transimission Control Protocol
,传输控制协议。
它是一种 面向连接的
、可靠的
、基于IP的
传输协议。
TCP在IP报文的协议号是6
二、TCP报文格式
2.1 TCP报文图片示例
- 中文版
- 英文版
2.2 TCP报文的具体内容
-
16位源端口号(
Source Port
):16位的源端口中包含初始化通信的端口。源端口和源IP地址的作用是标识报文的返回地址。
-
16位目的端口号(
Destination Port
):16位的目的端口域定义传输的目的。这个端口指明报文接收计算机上的应用程序地址接口。
-
32位序号(
Sequence Number
):32位的序列号由接收端计算机使用,重新分段的报文成最初形式。当SYN出现,序列码实际上是初始序列码(Initial Sequence Number,ISN),而第一个数据字节是ISN+1。这个序列号(序列码)可用来补偿传输中的不一致。
-
32位确认序号(
Acknowledgment Number
):32位的序列号由接收端计算机使用,重组分段的报文成最初形式。如果设置了ACK控制位,这个值表示一个准备接收的包的序列码。
-
4位首部长度(
Offset
):4位包括TCP头大小,指示何处数据开始。
-
保留(6位)(
Reserved
):6位值域,这些位必须是0。为了将来定义新的用途而保留。
-
标志(
TCP Flags
):6位标志域。表示为:紧急标志、有意义的应答标志、推、重置连接标志、同步序列号标志、完成发送数据标志。按照顺序排列是:URG、ACK、PSH、RST、SYN、FIN。
-
16位窗口大小(
Window
):用来表示想收到的每个TCP数据段的大小。TCP的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收的字节。窗口大小是一个16字节字段,因而窗口大小最大为65535字节。
-
16位校验和(
Checksum
):16位TCP头。源机器基于数据内容计算一个数值,收信息机要与源机器数值 结果完全一样,从而证明数据的有效性。检验和覆盖了整个的TCP报文段:这是一个强制性的字段,一定是由发送端计算和存储,并由接收端进行验证的。
-
16位紧急指针(
Urgent Pointer
):指向后面是优先数据的字节,在URG标志设置了时才有效。如果URG标志没有被设置,紧急域作为填充。加快处理标示为紧急的数据段。
-
选项(
TCP Choices
):长度不定,但长度必须为1个字节。如果没有选项就表示这个1字节的域等于0。
-
数据(
Data
):该TCP协议包负载的数据。
2.3 TCP Flags:主要操控TCP的状态机
-
URG
:此标志表示TCP包的紧急指针域(后面马上就要说到)有效,用来保证TCP连接不被中断,并且督促中间层设备要尽快处理这些数据; 【紧急标志。紧急标志为”1”表明该位有效。】
-
ACK
:此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1, 为1的时候表示应答域有效,反之为0;
【确认标志。表明确认编号栏有效。大多数情况下该标志位是置位的。TCP报头内的确认编号栏内包含的确认编号(w+1)为下一个预期的序列编号,同时提示远端系统已经成功接收所有数据。】
-
PSH
:这个标志位表示Push操作。所谓Push操作就是指在数据包到达接收端以后,立即传送给应用程序, 而不是在缓冲区中排队;
-
RST
:这个标志表示连接复位请求。用来复位那些产生错误的连接,也被用来拒绝错误和非法的数据包;
-
SYN
:表示同步序号,用来建立连接。
SYN标志位和ACK标志位搭配使用,当连接请求的时候,
SYN=1, ACK=0;
连接被响应的时候,SYN=1,ACK=1;
这个标志的数据包经常被用来进行端口扫描。扫描者发送 一个只有SYN的数据包,如果对方主机响应了一个数据包回来 ,就表明这台主机存在这个端口;但是由于这种扫描方式只是进行TCP三次握手的第一次握手,因此这种扫描的成功表示被扫描的机器不很安全,一台安全的主机将会强制要求一个连接严格的进行TCP的三次握手。
-
FIN
:表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送FIN标志 位的TCP数据包后,连接将被断开。这个标志的数据包也经常被用于进行端口扫描。
三、TCP的三次握手与四次挥手
- TCP的三次握手与四次挥手完整过程图例
3.1 三次握手
3.1.1 三次握手是什么
三次握手,Three-Way Handshake
,即建立TCP连接。而且建立一个TCP连接需要客户端和服务端总共发送3个包以确认连接的建立。
- 三次握手图例
3.1.2 三次握手过程解析
-
第一次握手:
客户端将标志
SYN
设置为1,随机产生一个值seq = J
,并将该数据包发送给服务器,此时,客户端进入SYN_SENT
状态,等待服务器的确认。 -
第二次握手:
服务器收到数据包后,由标志
SYN = 1
知道客户端的请求,并建立连接。此时,服务器将标识SYN
和ACK
都设置为1,ack = J + 1
;且随机产生一个值seq = K
,并将该数据包发送给客户端以确认连接请求。服务器也进入了SYN_RCVD
状态。 -
第三次握手:
客户端收到确认后,检测
ack
是否为J + 1
,ACK
是否为1,如果正确,则将标识位ACK
设置为1,ack = K + 1
,并将该数据包发送给服务器,服务器检查ack
是否为K + 1
,ACK
是否为1,如果正确,则连接建立成功,客户端和服务器都进入ESTABLISHED
状态,完成三次握手。
完成三次握手后,客户端和服务器之间就可以开始传输数据。
3.2 四次挥手
- 四次挥手图例
3.2.1 四次挥手是什么
四次挥手,Four-Way Wavehand
,即终止TCP连接。而且断开一个TCP连接,需要客户端和服务端总共发送4个包,才能确认连接断开。
3.2.2 四次挥手过程解析
-
第一次挥手:
客户端发送一个
FIN
,用来关闭客户端到服务器的数据传送,客户端进入FIN_WAIT_1
的状态。 -
第二次挥手
服务器收到
FIN
后,会发送一个ACK
给客户端,确认序号为收到序号 + 1(与SYN
相同,一个FIN
占用一个序号)。此时,服务器端进入CLOSE_WAIT
状态。 -
第三次挥手
服务器发送一个
FIN
,用来关闭服务器到客户端的数据传送,服务器进入LAST_ACK
状态。 -
第四次挥手
客户端收到
FIN
后进入TIME_WAIT
状态,接着客户端发送一个ACK
给服务器,确认号为收到序号 + 1;此时服务器进入CLOSED
状态,完成四次挥手。
3.3 SYN攻击
-
在三次握手过程中,
Server
发送SYN-ACK
之后,收到Client
的ACK
之前的TCP连接
称为半连接(half-open connect)
,此时Server
处于SYN_RCVD
状态,当收到ACK
后,Server
转入ESTABLISHED
状态。 -
SYN攻击
就是Client
在短时间内伪造大量不存在的IP地址
,并向Server
不断地发送SYN包
,Server
回复确认包,并等待Client
的确认,由于源地址是不存在的,因此,Server
需要不断重发直至超时,这些伪造的SYN
包将产时间占用未连接队列,导致正常的SYN请求
因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。 -
SYN攻击
时一种典型的DDOS
攻击,检测SYN攻击的方式非常简单,即当Server
上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN
攻击了,使用如下命令可以让之现行:
#netstat -nap | grep SYN_RECV
3.4 为什么要三次握手?
- 提一个问题:为什么非要三次呢?怎么觉得两次就可以完成了。那TCP为什么非要进行三次连接呢?
- 已失效的连接请求报文段突然又传送到了服务端,会出现问题。
- “已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。 但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。
- 假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。 这样,server的很多资源就白白浪费掉了。
- 采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。
简单理解:
因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。
3.5 为什么要四次分手?
-
TCP
是全双工模式,这就意味着,当Client
发出FIN
报文段时,只是表示Client
已经没有数据要发送了,Client
告诉Server
, 它的数据已经全部发送完毕了; -
但是,这个时候
Client
还是可以接受来自Server
的数据;当Server
返回ACK
报文 段时,表示它已经知道Client
没有数据发送了,但是Server
还是可以发送数据到Client
的; -
当
Server
也发送了FIN
报文段时,这个时候就表示Server
也没有数据要发送了,就会告诉Client
,我也没有数据要发送了,之后彼此 就会愉快的中断这次TCP
连接。
如果要正确的理解四次分手的原理,就需要了解四次分手过程中的状态变化。
-
FIN_WAIT_1
其实
FIN_WAIT_1
和FIN_WAIT_2
状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:
FIN_WAIT_1
状态实际上是当SOCKET
在ESTABLISHED
状态时, 它想主动关闭连接,向对方发送了FIN
报文,此时该SOCKET
即进入到FIN_WAIT_1
状态。而当对方回应ACK
报 文后,则进入到FIN_WAIT_2
状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK
报文,所以FIN_WAIT_1
状态一般是比较难见到的,而FIN_WAIT_2
状态还有时常常可以用netstat
看到。 (主动方) -
FIN_WAIT_2
实际上
FIN_WAIT_2
状态下的SOCKET
,表示半连接,也即 有一方要求close
连接,但另外还告诉对方,我暂时还有点数据需要传送给你(ACK
信息),稍后再关闭连接。 (主动方) -
CLOSE_WAIT
表示在等待关闭。
当对方
close
一个SOCKET
后发送FIN
报文给自己,系统毫无疑问地会回应一个ACK
报文给对方,此时则进入到CLOSE_WAIT
状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以close
这个SOCKET
,发送FIN
报文给对方,也即关闭连接。所以你在CLOSE_WAIT
状态下,需要完成的事情是等待你去关闭连接。(被动方) -
LAST_ACK
这个状态还是比较容易好理解的,它是被动关闭一方在发送
FIN
报文后,最后等待对方的ACK
报文。当收到ACK报文后,就可以进入到CLOSED
可用状态了。(被动方) -
CLOSED
表示连接中断。
简单理解:
关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送,但未必所有的数据都全部发送给对方,所以你未必会马上关闭SOCKET,也即你可能还需要发送一些数据给对方,之后再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。