• TCP三次握手和四次挥手


    1、tcp的各路状态

    简单说下TCP的三次握手和四次挥手的流程,说完这两个流程,就能把TCP的状态给涵盖上。

    2、tcp头部格式

    3、对于TCP三次握手和四次挥手,我们最主要的就是关注TCP头部的序列号、确认号以及几个标记位(SYN/FIN/ACK/RST)

    4、序列号:在初次建立连接的时候,客户端和服务端都会为「本次的连接」随机初始化一个序列号。(纵观整个TCP流程中,序列号可以用来解决网络包乱序的问题)

    5、确认号:该字段表示「接收端」告诉「发送端」对上一个数据包已经成功接收(确认号可以⽤来解决网络包丢失的问题)

    6、而标记位就很好理解啦。SYN为1时,表示希望创建连接。ACK为1时,确认号字段有效。FIN为1时,表示希望断开连接。RST为1时,表示TCP连接出现异常,需要断开。

    7、TCP三次握手的过程其实就是在:确认通信双方(客户端和服务端)的序列号

    8、在最开始的时候,客户端和服务端都处于 CLOSE 状态,服务器主动监听某个端口,处于 LISTEN 状态,客户端会随机生成出序列号(这里的序列号一般叫做client_isn),并且把标志位设置为SYN(意味着要连接),然后把该报文发送给服务端,客户端发送完SYN报文以后,自己便进入了 SYN_SEND 状态。

    9、服务端接收到了客户端的请求之后,自己也初始化对应的序列号(这里的序列号一般叫做 server_isn),在「确认号」字段里填上client_isn + 1(相当于告诉客户端,已经收到了发送过来的序列号了) ,并且把 SYN 和 ACK 标记位都点亮(置为1),把该报文发送客户端,服务端的状态变成 SYN-REVD 状态。

    10、 客户端收到服务端发送的报文后,就知道服务端已经接收到了自己的序列号(通过确认号就可以知道),并且接收到了服务端的序列号(server_isn)。此时,客户端需要告诉服务端自己已经接收到了他发送过来的序列号,所以在「确认号」字段上填上server_isn+1,,并且标记位 ACK 为1。

     11、客户端在发送报文之后,进入 ESTABLISHED 状态,而服务端接收到客户端的报文之后,也进入 ESTABLISHED 状态,这就是三次握手的过程以及涉及到的TCP状态。

    总结下来,就是双方都把自身的序列号发给对方,看对方能不能接收到。如果「确认可以」,那就可以正常通信。(三次握手这个过程就可以看到双方都有接收和发送的能力)

    12、两次握手行吗?

    两次握手只能保证客户端的序列号成功被服务端接收,而服务端是无法确认自己的序列号是否被客户端成功接收。所以是不行的。

    防止失效的连接请求报文段被服务端接收,从而产生错误。

    PS:失效的连接请求:若客户端向服务端发送的连接请求丢失,客户端等待应答超时后就会再次发送连接请求,此时,上一个连接请求就是『失效的』。

    若建立连接只需两次握手,客户端并没有太大的变化,仍然需要获得服务端的应答后才进入ESTABLISHED状态,而服务端在收到连接请求后就进入ESTABLISHED状态。此时如果网络拥塞,客户端发送的连接请求迟迟到不了服务端,客户端便超时重发请求,如果服务端正确接收并确认应答,双方便开始通信,通信结束后释放连接。此时,如果那个失效的连接请求抵达了服务端,由于只有两次握手,服务端收到请求就会进入ESTABLISHED状态,等待发送数据或主动发送数据。但此时的客户端早已进入CLOSED状态,服务端将会一直等待下去,这样浪费服务端连接资源。

    作者:Honest1y
    链接:https://juejin.cn/post/6992433321435201573
    来源:稀土掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    13、序列号为什么是随机的?以及序列号是怎么生成的?

    一方面为了安全性(随机ISN能避免非同一网络的攻击),另一方面可以让通信双方能够根据序号将「不属于」本连接的报文段丢弃。

    序列号怎么生成的?这…随便猜下就应该跟「时钟」和TCP头部的某些属性做运算生成的吧,类似于雪花算法(:具体我忘了。

    14、既然网络是不可靠的,那建立连接不是会经过三次握手吗?那要是在中途丢了,怎么办?

    假设第一个包丢了,客户端发送给服务端的 SYN 包丢了(简而要之就是服务端没接收到客户端的SYN包)。

    客户端迟迟收不到服务端的ACK包,那会周期性超时重传,直到收到服务端的ACK。

    假设第二个包丢了,服务端发送的SYN+ACK包丢了(简而要之就是客户端没接收到服务端的SYN+ACK包)。

    服务端迟迟收不到客户端的ACK包,那会周期性超时重传,直到收到客户端的ACK。

    假设第三个包丢了(ACK包),客户端发送完第三个包后单方面进入了 ESTABLISHED 状态,而服务端也认为此时连接是正常的,但第三个包没到达服务端。

    一、如果此时客户端与服务端都还没数据发送,那服务端会认为自己发送的SYN+ACK的包没发送至客户端,所以会超时重传自己的SYN+ACK包。

    二、如果这时候客户端已经要发送数据了,服务端接收到了ACK + Data数据包,那自然就切换到 ESTABLISHED 状态下,并且接收客户端的Data数据包。

    三、如果此时服务端要发送数据了,但发送不了,会一直周期性超时重传SYN + ACK,直到接收到客户端的ACK包。

    15、四次挥手

    在建立完连接之后,客户端和服务端双方都处于 ESTABLISHED 状态状态。

    断开连接双方都有权利的。

    客户端打算关闭连接,会发 FIN 报文给服务端(其实就是把标志位 FIN 点亮),客户端发送完之后,就进入FIN_WAIT_1状态。

    服务端收到 FIN 报文之后,回复 ACK 报文给客户端(表示已经收到了),服务端发送完之后,就进入 CLOSE_WAIT 状态。

    客户端接收到服务端的 ACK 报文,就进入了 FIN_WAIT_2 状态。

     16、这时候,服务器可能还有数据要发送给客户端,等服务端确认自己已经没有数据返回给客户端之后,就发送FIN报文给客户端了,自己进入 LAST_ACK 状态。

    客户端收到服务端的FIN报文之后,回应ACK报文,自己进入 TIME_WAIT 状态。

    服务端收到客户端的ACK报文之后,服务端就进入 CLOSE 状态。

     客户端在TIME_WAIT等到2MSL,也进入了 CLOSE 状态。

     17、四次挥手为什么是四次呢

    当客户端第一次发送 FIN 报文之后,只是代表着客户端不再发送数据给服务端,但此时客户端还是有接收数据的能力的。而服务端收到FIN报文的时候,可能还有数据要传输给客户端,所以只能先回复 ACK给客户端。

    等到服务端不再有数据发送给客户端时,才发送 FIN 报文给客户端,表示可以关闭了。所以,一来一回就四次了。

    18、从四次挥手的流程上来看,有个 TIME_WAIT 状态,你知道这个状态干什么用的吗?(等待 2MSL)

    主要有两个原因吧。1.保证最后的 ACK 报文 「接收方」一定能收到(如果收不到,对方会 重发 FIN 报文)2. 确保在创建新连接时,先前网络中残余的数据都丢失了。

    其实也比较好理解的。就正如我们重启服务器一样,会先优雅关闭各种资源,再留有一段时间,希望在这段时间内,资源是正常关闭的,这样重启服务器(或者发布)就基本认为不会影响到线上运行了。

    (为了保证B能收到A的确认应答。 若A发完确认应答后直接进入CLOSED状态,那么如果该应答丢失,B等待超时后就会重新发送连接释放请求,但此时A已经关闭了,不会作出任何响应,因此B永远无法正常关闭。)

    19、假设 TIME_WAIT 状态多过会有什么危害?怎么解决呢?

    从流程上看, TIME_WAIT 状态 只会出现在 主动发起 关闭连接的一方。危害就是会占用内存资源和端口呗(毕竟在等待嘛),解决的话,有Linux参数可以设置,具体忘了额。

    20、TCP连接,那这个连接到底是什么?你是怎么理解的?

    其实从三次握手可以发现的是,TCP建立连接无非就是交换了双方的状态(比如序列号)。然后就没有然后了…连接本质上「只是互相维持一个状态,有连接特性」。

    21、DOS攻击

    在黑客攻击事件中,SYN攻击是最常见又最容易被利用的一种攻击手法。

    SYN攻击属于DDoS攻击的一种,它利用TCP协议缺陷,通过发送大量的半连接请求,耗费CPU和内存资源。SYN攻击除了能影响主机外,还可以危害路由器防火墙等网络系统,事实上SYN攻击并不管目标是什么系统,只要这些系统打开TCP服务就可以实施。服务器接收到连接请求(syn= j),将此信息加入未连接队列,并发送请求包给客户(syn=k,ack=j+1),此时进入SYN_RECV状态。当服务器未收到客户端的确认包时,重发请求包,一直到超时,才将此条目从未连接队列删除。配合IP欺骗,SYN攻击能达到很好的效果,通常,客户端在短时间内伪造大量不存在的IP地址,向服务器不断地发送syn包,服务器回复确认包,并等待客户的确认,由于源地址是不存在的,服务器需要不断的重发直至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,目标系统运行缓慢,严重者引起网络堵塞甚至系统瘫痪。

    关于SYN攻击防范技术,人们研究得比较早。归纳起来,主要有两大类,一类是通过防火墙路由器等过滤网关防护,另一类是通过加固TCP/IP协议栈防范

    SYN Flood利用TCP协议缺陷,发送了大量伪造的TCP连接请求,使得被攻击方资源耗尽,无法及时回应或处理正常的服务请求。一个正常的TCP连接需要三次握手,首先客户端发送一个包含SYN标志的数据包,其后服务器返回一个SYN/ACK的应答包,表示客户端的请求被接受,最后客户端再返回一个确认包ACK,这样才完成TCP连接。在服务器端发送应答包后,如果客户端不发出确认,服务器会等待到超时,期间这些半连接状态都保存在一个空间有限的缓存队列中;如果大量的SYN包发到服务器端后没有应答,就会使服务器端的TCP资源迅速耗尽,导致正常的连接不能进入,甚至会导致服务器的系统崩溃。

    ==============================

    22、客户端发送的 ACK 在网络中被丢了。那怎么办?

    • 其实大部分时候,我们连接建立完成就会立刻发送数据,所以如果服务端没有收到 ACK 没关系,当收到数据就会认为连接已经建立;
    • 如果连接建立后不立马传输数据,那么服务端认为连接没有建立成功会周期性重发 SYN&ACK 直到客户端确认成功。

    23、4次握手,其实为了保证可靠性,这个握手次数可以一直循环下去;但是这没有一个终止就没有意义了。所以3次,保证了各方消息有来有回就足够了。

    24、为什么2次握手不行呢?

    2次握手我们可以想象是没有三次握手最后的 ACK, 在实际中确实会出现客户端发送 ACK 服务端没有收到的情况(上面的情况一),那么这是否说明两次握手也是可行的呢?

    2次握手当服务端发送消息后,就认为建立成功,而恰巧此时又没有数据传输。这就会带来一种资源浪费的情况。比如:客户端可能由于延时发送了多个连接情况,当服务端每收到一个请求回复后就认为连接建立成功,但是这其中很多求情都是延时产生的重复连接,浪费了很多宝贵的资源。 

    从资源节省、效率3次握手都是最合适的。 

    25、

    抓包:

    1. sudo tcpdump -n host www.baidu.com -S
    2. S 表示 SYN
    3. . 表示 ACK
    4. P 表示 传输数据
    5. F 表示 FIN

    26、一个端口可以建立多少个tcp连接

    事实上Linux内核对TCP连接的识别是通过四元组来区分,即(源ip,源port,目标ip,目标port)。这个四元组只要任意一个不同,就是完全不同的连接!所以说,只要建立的连接是不同的,一个端口是可以建立多个TCP连接的!

     

    当客户端调用 connect() 时候就会发起三次握手,这次握手的时候有几个元素唯一确定了这次通信(或者说这个socket),[源IP:源Port, 目的IP:目的Port] ,当然这个socket还不是最终用来传输数据的socket,一旦握手完成后,服务端会在返回一个 socket 专门用来后续的数据传输。这里暂且把第一个socket叫 监听socket,第二个叫 传输socket 方便后文叙述。

    为什么要这么设计呢?大家想一想,如果监听的socket还要负责数据的收发,请问这个服务端的效率如何提升?什么东西、谁都往这个socket里边丢,太复杂!

    27、在Linux系统中,表示端口号(port)的变量占16位,这就决定了端口号最多有2的16次方个,即65536个,另外端口0有特殊含义不给使用,这样每个服务器最多就有65535个端口可用。因此,65535代表Linux系统支持的TCP端口号数量,在TCP建立连接时会使用。

    IP地址是32位的。

    因此最大支持创建TCP个数为2的32次方(IP地址是32位的)乘以2的16次方(port是16位的)等于2的48次方。

    28、最大文件描述符数量

    查看用户级别文件描述符限制

    每个tcp连接都要占用一定内存,每个socket就是一个文件描述符

    ulimit -n

    文件描述符是服务器程序的宝贵资源,几乎所有系统调用都是和文件描述符打交道。而系统分配给进程的文件描述符数量有限,因此需要及时关闭那些不用的文件描述符。

    Linux对应用程序能打开的最大文件描述符数量,有2个层次限制:用户级限制,系统级限制。
    1)用户级限制,是指目标用户运行的所有进程总能打开的文件描述符数量;
    2)系统级限制,是指所有用户总共能打开的文件描述符数量。

    29、在现实场景中,由于存在端口port复用的情况,服务器可同时支持的TCP连接数跟65535没有一一对应关系,事实上,真正影响TCP连接数量的,是服务器的内存以及允许单一进程同时打开文件的数量,因为每创建一个TCP连接都要创建一个socket句柄,每个socket句柄都占用一部分系统内存,当系统内存被占用殆尽,允许的TCP并发连接数也就到了上限。一般来讲,通过增加服务器内存、修改最大文件描述符个数等,可以做到单台服务器支持10万+的TCP并发。 

  • 相关阅读:
    《少有人走的路:心智成熟的旅程》笔记
    python学习笔记——条件、循环和异常
    Hot 100总结【leetcode】
    Redis整数集合
    HTML学生个人网站作业设计——中华美食(HTML+CSS) 美食静态网页制作 WEB前端美食网站设计与实现
    202.快乐数
    Bond网卡
    C++:计算两个二维/三维向量间夹角
    HTML网页设计制作大作业(游戏主题)---电竞
    35.JavaScript对象和数组的解构赋值基础详解、let陷阱、函数参数解构
  • 原文地址:https://blog.csdn.net/han_jr123/article/details/127409696