1.TCP三次握手过程和状态变迁
TCP是面向连接的协议,所以使用TCP前必须先建立连接,而建立连接是通过三次握手来进行的。
- 一开始,客户端和服务端都处于CLOSED状态。先是服务端主动监听某个端口,处于LISTEN状态
- 客户端会随机初始化序号client_isn,将此序号置于TCP首部的序号字段中,同时把SYN标志位置为1,表示SYN报文。客户端向服务端发送第一个SYN报文,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于SYN-SENT状态。
- 服务端收到客户端的SYN报文后,首先服务端也随机初始化自己序列号server_isn,将此序列号填入TCP首部的序号字段中,其次把TCP首部的确认应答号字段填入client_isn+1,接着把SYN和ACK标志位置为1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于SYN_RCVD状态。
- 客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文的首部ACK标志位置为1,其次确认应答号字段填入server_isn+1,最后把报文发送给服务端,这次报文可以携带客户到服务器的数据,之后客户端处于ESTABLISHED状态。
- 服务器收到客户端的应答报文后,也进入ESTABLISHED状态。
从上面的过程可以发现第三次握手是可以携带数据的,前两次握手是不可以携带数据的。
一旦完成三次握手,双方都处于ESTABLISHED状态,此时连接就已经建立完成,客户端和服务端就可以相互发送数据了。
2.如何在Linux系统中查看TCP状态
TCP的连接状态查看,在Linux可以通过netstat-napt命令查看。
3.为什么是三次握手?不是两次、四次?
- 三次握手才可以阻止重复历史连接的初始化(主要原因)
- 三次握手才可以同步双方的初始化序列化。序列号能保证数据包不重复、不丢弃和按序传输。
- 三次握手才可以避免资源浪费
为什么不是两次、四次:
- 两次:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号。
- 四次:三次握手就已经理论最少可靠连接建立,所以不需要使用更多的通信次数。
4.为什么客户端和服务端的初始序列号ISN是不相同的?
- 如果序列号相同就无法分辨历史报文。
- 同时为了安全性,防止黑客伪造相同序列号的TCP报文被对方接收。
5.既然IP层会分片,为什么TCP层还需要MSS呢
- MTU:一个网络包的最大长度,以太网中一般为1500字节。
- MSS:除去IP和TCP头部之后,一个网络包所能容纳的TCP数据的最大长度
如果只进行IP层以MTU大小进行分片,如果其中一个IP分片丢失,整个IP报文的所有分片都需要重传。
并且因为IP层没有超时重传机制,所以需要TCP层发起超时重传。这样的效率很低。
因此为了达到最佳的传输效能,建立连接的时候通常需要协商双方的MSS值,当TCP层发现数据超过MSS时,则就会先进行分片,在这个基础上就不需要进程IP分片了。
经过TCP层分片后,如果一个TCP分片丢失,进行重发时也是以MSS为单位,而不用重传所有的分片,大大增加了重传的效率。
6.什么是SYN攻击?如何避免SYN攻击
攻击者短时间伪造不同IP地址的SYN报文,服务端每接到一个SYN报文,就进入SYN_RCVD状态,当服务端发送出去的ACK+SYN报文,无法得到未知IP主机的ACK应答,久而久之就会占满服务端的SYN接收队列(未连接队列)使得服务器不能为正常用户服务。
避免:
- 修改Linux内核参数,控制队列大小和当队列满时应当做什么处理
- 当网卡接收数据包的速度大于内核处理的速度时,会有一个队列保存这些数据包。控制该队列的最大值如下参数:
net.core.netdev_max_backlog - SYN_RCVD状态连接的最大个数
net.ipv4.tcp_max_syn_backlog - 超出处理能时,对新的SYN直接回报RST,丢弃连接:
net.ipv4.tcp_abort_on_overflow
- 当网卡接收数据包的速度大于内核处理的速度时,会有一个队列保存这些数据包。控制该队列的最大值如下参数:
- 通过cookie值,直接将SYN+ACK值返回给服务端处理,如果服务端确认ACK合法,建立连接。