TCP的三次握手
TCP的主要特点
- 面向连接的运输层协议。通过ip识别唯一主机、端口号识别进程,完成进程之间的通信。
- 点对点,即每一条TCP连接只能有两个端点。
- 提供可靠的服务,承诺数据无差错、不丢失、不重复、按序到达。
- 提供全双工通信,允许通信双方的应用进程在任何时候都能发送数据。
- 面向字节流
TCP报文段中的控制位
确认ACK(ACKnowledgment) 仅当ACK=1时确认号字段有效,当ACK=0时,确认号无效。TCP规定,在连接建立后所有传送的报文段都必须把ACK置为1.
同步SYN(SYNchronization) 在连接建立时用来同步序号。当SYN=1&&ACK=0时,表明这是一个连接请求报文段。双方若同意建立连接,则应在响应的报文段中声明SYN=1和ACK=0。
TCP的连接建立
三次握手的过程假设client主动打开连接,server被动打开连接。
一开始,B的TCP服务器进程先创建传输控制块TCB,准备接受客户进程的连接请求,此时服务器进入LISTEN(收听)状态,等待客户的连接请求。
A的TCP客户进程也是首先创建TCB,然后在打算建立TCP连接的时候,向B发送连接请求报文段,这时首部中的同步位SYN=1,同时选择一个初始化序号seq=x。TCP规定,SYN报文段(即SYN=1的报文段)不能携带数据,但是要消耗一个序号。此时,客户进程进入SYN-SENT(同步已发送)状态
B收到连接请求报文段后,如果同意建立连接,则向A发送确认。在确认报文段中应把SYN位和ACK位都置为1,确认号是ack=x+1,同时也为自己选择一个初始序号seq=y。由于是SYN报文段,此时也是不可以携带数据的,但是需要消耗一个序号。此时,服务器进程进入SYN-RCVD(同步收到)状态
客户进程收到服务器进程的确认后,还需要向服务器进程给出确认。确认报文段的ACK置为1去,确认号ack=y+1,而自己的序号seq=x+1。TCP的标准规定,ACK报文段可以携带数据,但如果不携带数据则不消耗序号。此时,连接已建立,A进入ESTABLISHED(已建立连接)状态.
服务器进程收到确认后,也进入ESTABLISHED(已建立连接)状态.
为什么要进行三次握手?两次握手不可以么?
这主要是为了防止已失效的连接请求报文段突然又传到了服务器,因而产生错误。
第一次丢失,第二次到达
以下主要讨论两种情况下,三次握手的好处。
这个时候,两次握手是没有问题的,不存在“已失效的连接请求报文段”
下面我们来讨论一下,如果第一次的请求并没有丢失,经过一段时间后,它又到达了服务器
第一次延迟,第二次到达
这时,如果采用三次握手,第二次服务器向客户端发起连接应答时,客户端会忽略这条请求,服务器由于没收到客户端的确认,就知道客户端此时没有要求建立连接。
建立连接的过程中,可以携带数据么?
第一第二次是SYN包,不可以携带数据,第三次ACK包可以携带数据。
首次握手过程中,存在什么隐患?
SYN Flood.即黑客伪造请求,一直向Server发送建立连接请求,但不回复ACK包,由于处于"半连接"状态,Server会尝试重新发送SYN-ACK,直到超过一定时间后,才关闭连接。(Linux服务器默认为63秒
1+2+4+8+16+32
),如此,服务器的连接队列就会被耗尽,当真正的请求到达时,无法做出响应。
如何防范SYN Flood
SYN队列满后,通过tcp_syncookies参数回发SYN Cookie(通过源IP地址端口,目的地址端口和时间戳来确定的一个seq),此时只有正常的客户端收到该cookie之后会回发SYN Cookie,并建立连接。
在建立连接中,客户端出现故障时,TCP是如何处理的?
TCP设有一个保活计时器,服务器每收到一次客户的数据,就重新设置保活计时器,时间的设置通常是两小时,如果两小时没有收到客户的数据,服务器就发送一个探测报文段,以后每隔75秒发送一次,如果连续10次发送报文段客户端依然不回复,那么就会关闭这个连接。