经典计算机网络知识点
详细介绍一下TCP的三次握手机制,为什么需要三次握手
TCP报文段中有两个重要的字段:序号字段(seq)和确认号字段(ack),这两个字段在握手阶段和传输信息过程中起到至关重要的作用。
ACK、SYN表示标志位,其值为1或0;seq代表报文段的序号,ack代表期望收到的下一个报文段的序号。
- 第一次握手:客户端client的TCP会首先向服务端server的TCP发送一个不携带额外数据的特殊TCP报文段,该报文段的SYN(Synchronize Sequence Numbers)标志位会被置为1(表示请求建立连接,这是连接请求报文),故该报文段被称为SYN报文段。此时客户端会随机选取一个初始序列号(client_x),并把该编号放置在序号字段seq中,最后将报文段封装成IP数据包通过层层传递发送给server。
- 第二次握手:server端接收到SYN报文段后,会为该TCP分配缓存和变量,并发送同意连接的SYN-ACK报文段。在该报文段中,SYN标志位仍被置为1,ACK标志位被置为1(表示同意确认建立连接,这是连接接受报文),而确认号字段ack则会放置client_x+1的值,然后服务端也会随机生成一个server_y编号存放到该报文段的序号字段seq中,最后将该报文段封装成IP数据包回传给client。
- 第三次握手:client端接收到SYN-ACK报文段后,知道了server端能够正常接收自己发送的数据,还需要让服务端知晓自己也能够正常接收其发送的数据,故最后也需向server端发送一个ACK报文段。该报文段中,SYN标志位被置为0(表示握手完成),ACK标志位为1,确认号字段ack放置server_y+1的值,序号字段seq则存放client_x+1,且该报文段可以携带数据。
一旦完成上述三个步骤,则表示客户端和服务器进入了ESTABLISHED(TCP连接成功)状态,完成三次握手,可以互相发送携带数据的报文。
三次握手恰好,两次的话server端不知道client端是否能正常接收,四次的话就多余了。
什么是SYN超时,洪泛攻击,有什么解决策略
- 由于在TCP连接的第一次握手中,client会向server端发送SYN报文段,server端收到后为该TCP初始化连续变量和分配缓存,然后server端会回发SYN-ACK报文段响应,并等待来自client端的ACK报文段;若client不完成第三次握手,由于TCP的可靠性,服务器会在终止半开连接并在SYN-RECV队列中移除该TCP之前等待相当长一段时间,这就给经典的DoS攻击,也就是SYN洪泛攻击提供了场景。只要恶意攻击者向服务器发送大量的SYN报文段,而不完成第三次握手,或在SYN报文段里通过欺骗源IP地址,让服务器响应SYN-ACK报文段到假的IP,从而永远收不到ACK,此时大量的SYN报文段接踵而至,会使得server端不断为这些半开连接分配资源,最终耗尽服务器资源,导致内存溢出无法服务。
常见解决方案,采用SYN cookie机制:
- 当server接收到一个SYN报文段时,因为他不清楚这个是合法的连接请求还是恶意攻击,故不会直接为该TCP分配资源,仅打开一个半开的套接字维持连接。然后服务器会根据接收到的SYN报文段中的源IP、目的IP,端口号以及只有自己知道的秘密数,通过复杂散列函数生成一个cookie,然后将该cookie作为序号字段的值响应给client(服务器并不记忆该cookie或任何对应于SYN的其他状态信息)
- 若client是正常合法用户连接,将会返回确认号字段为cookie+1的报文段,server端收到ACK后,会再根据ACK报文段的源IP、目的IP,端口号和秘密数通过散列函数计算出结果,然后判断结果值加1是否等于确认号字段的值,若相等则证明是刚刚请求连接的合法客户端,然后才为该TCP分配资源。(若收不到ACK,或判断不对,则不会分配,避免了恶意攻击)
详细介绍一下TCP的四次挥手机制,为何会有TIME_WAIT状态,为何断开连接需要四次握手,服务器出现大量CLOSE_WAIT状态如何解决
- 首先TCP全双工连接,双方都可以发起关闭连接的请求,每个方向都必须单独进行关闭操作。以client端先发起关闭连接请求为例:当client完成其数据发送任务后就可以发送一个携带FIN标志位的报文段来关闭这个方向的连接,该FIN标志位被置为1。(和SYN相同,FIN也会占用一个序号字段)server端收到FIN只能表明在到接收方的这个方向上没有数据传输,一个TCP连接在收到一个FIN后仍能发送数据,因而服务器会响应客户端一个确认报文(为收到的序号字段+1),并发送FIN标志位为1的终止报文来关闭他这个方向上的连接,最后客户端响应对应的确认报文,服务器收到ACK报文后立即断开连接,客户端等待一段时间后也断开连接。
先发起关闭的一方执行主动关闭,另一方执行被动关闭,简写如下:(先关读,后关写)
- server读通道关闭
- client写通道关闭
- client读通道关闭
- server写通道关闭
详细过程如下:
- Client调用close(),给Server发送FIN报文段,序号为i,请求关闭连接;Server收到FIN后,返回Client确认ACK,序号为i+1,同时关闭Server读通道,即不能再从这个连接上读取东西,现在read()返回0。此时Server的TCP状态转化为CLOSE_WAIT状态。
- Client收到ACK后,关闭Client写通道,不再向连接中写入任何数据。
- Server调用close()关闭连接&