TCP(Transmission Control Protocol,传输控制协议)是基于连接的协议,也就是说,在正式收发数据前,必须和对方建立可靠的连接,就好像你给别人打电话,必须等线路接通了、对方拿起话筒建立了连接才能相互通话。
一个TCP连接必须要经过三次“对话”才能建立起来,其中的过程非常复杂,我们这里只做简单、形象的介绍,你只要做到能够理解这个过程即可。我们来看看这三次对话的简单过程:主机A向主机B发出连接请求数据包:“我想给你发数据,可以吗?”,这是第一次对话;主机B向主机A发送同意连接和要求同步(同步就是两台主机一个在发送,一个在接收,协调工作)的数据包:“可以,你什么时候发?”,这是第二次对话;主机A再发出一个数据包确认主机B的要求同步:“我现在就发,你接着吧!”,这是第三次对话。三次“对话”的目的是使数据包的发送和接收同步,经过三次“对话”之后,主机A才向主机B正式发送数据。
1. 建立连接三次握手
TCP用三次握手(three-way handshake)过程创建一个连接。在连接创建过程中,很多参数要被初始化,例如序号被初始化以保证按序传输和连接的强壮性。
一对终端同时初始化一个它们之间的连接是可能的。但通常是由一端打开一个套接字(socket)然后监听来自另一方的连接,这就是通常所指的被动打开(passive open)。服务器端被被动打开以后,用户端就能开始创建主动打开(active open)。
1)客户端通过向服务器端发送一个SYN来创建一个主动打开,作为三路握手的一部分。客户端把这段连接的序号设定为随机数 A。
2)服务器端应当为一个合法的SYN回送一个SYN/ACK。ACK 的确认码应为 A+1,SYN/ACK 包本身又有一个随机序号 B。
3)最后,客户端再发送一个ACK。当服务端受到这个ACK的时候,就完成了三路握手,并进入了连接创建状态。此时包序号被设定为收到的确认号 A+1,而响应则为 B+1。
Win:窗口字段明确指出现在允许对方发送的数据量(经常变化)
Len:TCP数据段长度
MSS(Maximum Segment Size):最大报文段长度,即每个TCP报文段中的数据字段的最大长度.这里需要在握手的时候进行协商,双方都给出MSS,最后以最小MSS确定为最终的MSS。IP数据报最大传输单位为MTU(Maximum Transmission Unit,Effect of short board),对于大多数使用以太网的局域网来说,MTU=1500。MSS往往基于MTU计算出来,通常MSS=MTU-sizeof(IP Header)-sizeof(TCP Header)=1500-20-20=1460,如果服务器MSS=1460,而客户端的MSS=1440,最终为1440。
在TCP的三次握手中,不仅是建立了连接,还让双方交换了有效信息,过程如下:
1) 嗨~ , 这是我sequence number和MSS
2) 我收到啦~, 这是我sequence number和MSS
3) 我也收到~
为什么需要三次握手?
简单地说,就是要保证在一段有效时间内,双方收到对方的有效信息。
一个简单例子,A发给B,B回复A,如果A不再回复B,B如何知道A收到了自己的信息?
谢希仁版《计算机网络》中的例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”。
不管哪个例子,都是为了满足”在不可靠信道上可靠地传输信息”这一需求。请注意这里的本质需求,信道不可靠,数据传输要可靠。还是那句话,就是要保证在一段有效时间内,双方收到对方的有效信息。
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攻击。
Socket状态对应
Socket API 和 TCP 协议中各个状态是如何对应的呢?我们可以通过下图来看:
2. 断开连接四次挥手
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。比如服务器收到一个FIN只意味着客户端不再发送数据,但它还可以向客户端发送数据,当服务器不再发数据了,他也要向客户端发送FIN。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
四次挥手过程如下:
1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。
2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A。
4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。
状态变化
FIN_WAIT_1: 当SOCKET在ESTABLISHED状态,主动关闭连接时,向对方发送FIN报文,此时该SOCKET进入到FIN_WAIT_1状态。当对方回应ACK报文后,则进入到FIN_WAIT_2状态。(主动方)
FIN_WAIT_2:处于FIN_WAIT_2状态下的SOCKET为半连接状态,等待对方发起断开要求,(注意对方可以在断开时捎带信息)稍后再关闭连接。(主动方)
TIME_WAIT: 收到了对方FIN报文,并发送出了ACK报文,等待2MSL后即可回到CLOSED状态了。
注意:在FIN_WAIT_1状态下,如果收到了对方同时带FIN和ACK标志的报文(复用一个报文)时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。(主动方)
CLOSING(比较少见): 如果双方几乎同时试图断开一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,即会出现CLOSING状态,表示双方都试图关闭SOCKET连接。
CLOSE_WAIT: 等待关闭连接,当对方发送FIN报文,回应ACK报文给对方后,则进入到CLOSE_WAIT状态。如果此时没有数据发送给对方,就可以关闭这个SOCKET,发送FIN报文给对方,即关闭连接。(被动方)
LAST_ACK: 被动关闭方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,进入到CLOSED状态。(被动方)
CLOSED: 连接中断。
Socket状态变化
参考:
https://zh.wikipedia.org/wiki/%E4%BC%A0%E8%BE%93%E6%8E%A7%E5%88%B6%E5%8D%8F%E8%AE%AE
http://www.kuqin.com/shuoit/20141018/342719.html
http://hackerxu.com/2014/11/16/TCP.html
https://www.centos.bz/2012/08/tcp-establish-close/
http://blog.csdn.net/xifeijian/article/details/12777187
http://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html
http://blog.163.com/[email protected]/blog/static/13222965520118139252103/
https://commons.wikimedia.org/wiki/File:Tcp_close.svg
版权声明:本文为博主原创文章,未经博主允许不得转载。