编程基础--tcp/ip协议(2)
三次握手与四次挥手就在这里发生。
TCP协议的三次握手和四次挥手在面试中经常会被问到!在一般的web开发中很少使用到,了解tcp可以更清楚的知道你的应用中,数据是如何传输的。
TCP协议
TCP协议的实现在OSI5层协议的传输层。TCP 协议可以保证数据通信的完整性和可靠性,还可以防止丢包。
TCP协议由头部和数据组成
tcp头
序列号(seq):占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号seq就是这个报文段中的第一个字节的数据编号。
确认号(ack):占4个字节,期待收到对方下一个报文段的第一个数据字节的序号;序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1即为确认号。
确认ACK:占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效。
同步SYN:连接建立时用于同步序号。当SYN=1,ACK=0时表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使得SYN=1,ACK=1。因此,SYN=1表示这是一个连接请求,或连接接受报文。SYN这个标志位只有在TCP建产连接时才会被置1,握手完成后SYN标志位被置0。
终止FIN:用来释放一个连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接。
tip:
ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;
初始化序列号(ISN)
(1) 当发送的数据为请求报文段时,序列号又称为初始化序列号(ISN),后续的序列号都从这个开始计算
(2) 为了防止数据传输过程中,有第三方伪造数据,因此初始化序列号不能从0开始,也不能容易被猜到,因此现在的系统都采用了半随机化的算法。
# 随机算法示例 ISN = M + F(localhost, localport, remotehost, remoteport). M是一个计时器,这个计时器每隔4毫秒加1。 F是一个Hash算法,根据源IP、目的IP、源端口、目的端口生成一个随机数值。要保证hash算法不能被外部轻易推算得出,用MD5算法是一个比较好的选择。
### 三次握手(建立连接)
在tcp发送数据前,先需要与通讯目标进行通讯确认。一般发送端为客户端,接受端为服务端,服务端处于listen状态
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;此时发送的seq值即ISN。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=ISN),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
完成三次握手即可开始接受数据。
tip:
除了第一次握手ACK为0,其余情况ACK都为1
握手成功前,对方难道不可以将数据缓存下来,等握手成功再提交给应用程序?
不可以,如果攻击者伪造了大量的握手报文,携带了1K+ 字节的数据,而接收方会开辟大量的缓存来容纳这些巨大数据,内存会很容易耗尽,从而拒绝服务。
为何第三次就可以携带数据?
因为进行第三次握手的主机在第二次时就接受到了对方的同意回应,自己也已经确认对方的安全。虽然服务端还未建立连接,但是在服务端接受到第三次握手的时候,就会切为建立好连接的状态,此时正常处理数据就行。
为什么序列号被仿造容易被攻击?
因为发送端可以伪造发送IP及发送信息,当知道序列号时,服务端就会将攻击者发送的信息做为正常客户端发送的数据进行处理。
四次挥手
第一次挥手:客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
第二次挥手:服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
第三次挥手:服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
第四次挥手:客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
tip:
最长报文寿命:
Windows : MSL = 2 min linux(Ubuntu, CentOs) : MSL = 60s Unix : MSL = 30s
为什么客户端要等待2MSL
发送的数据在网络条件差的情况下,可能需要1个MLS,如果数据丢失,服务端再返回来也可能需要1个MLS
tcp是如何保证数据不丢失的
tcp数据传输过程中,接受端每收到一条数据,那么久需要给发送端发一条确认消息。如果发送端没有收到,则确认这条数据丢失。
tip:
tcp如何确定传输速度的
丢包的情况。如果丢包过多,就会降低发送速度。
header中的窗口大小,在接受端,没有返回确认信息时,窗口控制代表发送到可以提前发送的数据的量。
other:
服务器可以接受多少个tcp连接?
服务端一般只监听一个端口进行通讯,因此连接数不受端口限制,一般通过服务器参数优化进行调优,比如:TCP/IP 协议栈调优,最大文件描述符调整
可以使用tcp代替udp吗?
udp会丢失数据,最好的udp实践就是TCP,一般udp会用在对延时比较敏感,且无法在客户端进行其他处理(比如:动画掩盖)的时候。
半连接池限制的是tcp同一时刻的请求数,而非连接数。
服务端大量处于time_wait是代表处于高并发