TCP的三次握手 四次挥手以及TCP的11种状态

三次握手流程:

客户端给服务端发送数据时,数据包中带有一个头,这个头就是前几十个字节,就是下面这张图。从源端口号,目的端口号,一直到序列号,直到Options。第一个包会将这前十几个字节中的SYN置1然后在Sequence Number中填充了一个值。而服务器回ACK的时候则是把ACK置1,把SYN置1,然后把32bits的Sequence Number填充,再将32bits的Acknowledgment Number填充,再发回给客户端。最后再回一个ACK,其实就是将ACK位置1,填充32bits的ACK,再发回给服务端,至此三次握手结束。

客户端连接服务器后,服务器处于一个listen的状态,此时服务端允许三次握手。

三次握手

1、客户端是在哪个函数?

connect

2、服务端是在哪个函数?

int clientfd = accept(fd,);

accept的流程

1、从accept的队列里面取出一个节点

2、为这个节点分配一个fd

所以我们再次思考 三次握手在服务端的哪个函数,你必须排除调accept,因为在accept时,三次握手早已结束,同时你又要排除掉listen,因为在三次握手的时候,listen早就返回了。因此三次握手,在哪个函数都没有发生,他是一个被动完成的过程。

注意这个过程:

服务器在接收到一个客户端的连接请求的时候,为他专门分配了一个节点。这个节点与socket一点关系都没有,他只是一个半连接。

再往后,客户端接收到服务端的ack之后,再给服务端回一个ack的时候,服务端需要将半连接的节点,放到accept中全链接的队列,那么这里就有一个问题?:

服务端怎么知道要从半连接队列中选择哪个节点(这个所谓的节点,其实就是一个连接,TCP的每一个连接都有一个这样的节点,叫做TCP的控制块TCB,伴随这个整个TCP的连接生命周期,TCP的11个状态,就保存在这个控制块中),放到全链接队列中。

如何在半连接队列里面,找到对应节点?

端口65535个,为什么大台服务器能够做到几百万的并发连接?

其实就是通过最后ACK的数据包中的五元组,通过这五个元素。

五元组(srcip源ip,srcport源端口,dstip目的ip,dstport目的端口,proto协议) 前面两个问题都可以用五元组回答,只要连接里,有任何一个不一样,就可以建立一个连接。

proto的作用:

tcp可以监听8080的端口,同时udp也可以在8080的端口进行receive。

说白了就是 tcpfd-->tcp:8080

udpfd-->udp:8080 可以同时工作

所以上面说的:

accept的流程

1、从accept的队列里面取出一个节点

2、为这个节点分配一个fd

从一开始创建这个fd开始 就生成了一个tcb

fd-->tcb

我们思考两个函数

send(fd,buffer,length,0)

rec(fd,buffer,length,0)

send是怎么发出去的,而rec又是如何接收到数据的?

其实原因就在于,这个fd映射了tcb.

send返回正数,是不是表示发送成功了?答案是不是。

尽管tcp是一个可靠协议,但send其实就是写入发送缓冲区而已,真正发还是要内核空间发,都是协议栈决定的,两个步骤是异步的。

接着讲一下四次挥手

四次挥手 不分客户端服务器 只分主动或者是被动

主动放发送fin(调用close函数) 被动方发送ack

接着被动方发送fin 主动方发送ack

那么有一个问题,主动方调用了close,被动方是如何知道的?其实就是recv返回0

返回0之后 我们再调用close函数 再回fin 对方收到返回ack后 四次挥手才结束。

最后讲一下 TCP的状态迁移

以上图为例,讲述四次挥手的过程

主动方,主动调用close函数,发送fin。主动方在收到ACK之前,TCP状态均从原本的establised,变更为FIN_WAIT_1(从close到fin_wait_1)

主动方收到被动方的ACK后,TCP状态变为FIN_WAIT_2,直到收到被动方发送的fin之前。

在主动方收到被动方的fin之后,立即返回ack后,主动方Tcp的状态为time_wait

我们再看被动方,在接收了FIN之后,立即返回ACK,被动方的TCP状态从原本的established变为close_wait.

接着被动方再发送完fin之后,进入last_ack状态。

那么现在有一个问题,双方同时调用close,会出现什么状态。

其实是会出现一个closing的状态。closing的状态还会在主动方发送fin后,被动方的ack包丢失的情况。

如果出现大量的time_wait是什么原因?

比如服务器出现大量的time_wait是什么原因,有什么解决方案?

前提你要明白,服务器之所以出现大量time_wait的前提是主动方主动调用close,才会出现。服务器主动关闭了大量的socket,其实现象是并不多的,作为服务器,一般是由客户端主动去处理的。

如果服务器出现大量time_wait?

1、代码逻辑上面出现了问题

如果客户端出现大量fin_wait_2?

发送这个问题说明:

在receive返回0,一直到调用close的中间这段时间,太长了!很有可能服务端的代码,根本没有调用close_wait,需要由服务端去查,很有可能没有调用close。

fin_wait_2如何终止?

答案是终止不了,通过看图就可以发现fin_wait_2,没有进入closing的路径。但凡没有的,你只能Kill进程结束

备注:(正常情况下,主动关闭连接的一端(客户端)在 FIN_WAIT_2 状态等待一段时间后,会收到对端(服务器)的FIN报文,从而进入TIME_WAIT状态等待连接的真正关闭。(服务器何时发送FIN取决于服务器应用程序的处理,一般会在read返回0发现客户端已经关闭连接后,也调用close关闭连接)

然而有在某些异常情况下,可能处于 FIN_WAIT_2 状态的一端一直等不到对端的FIN。如果没有外力的作用,连接两端会一直分别处于 FIN_WAIT_2 和 CLOSE_WAIT 状态。这会造成系统资源的浪费,需要对其进行处理。(注意内核协议栈就有参数提供了对这种异常情况的处理,无需应用程序操作)

目前的做法是:如果应用程序调用的是完全关闭(而不是半关闭),那么内核将会起一个定时器,设置最晚收到对端FIN报文的时间。如果定时器超时后仍未收到FIN,且此时TCP连接处于空闲状态,则TCP连接就会从 FIN_WAIT_2 状态直接转入 CLOSED 状态,关闭连接。

在Linux系统中可以通过参数 net.ipv4.tcp_fin_timeout 设置定时器的超时时间,默认为 60 s。)

滑动窗口 逐步递增的输送数据包

慢启动

拥塞控制

netstat -anop | grep 9096查看端口状态 以及是否被占用

会出现可以传输数据,但在用netstat无法查看到,说明走的不是操作系统的协议栈。用户态的协议栈。

相关推荐
专注VB编程开发20年4 分钟前
WebSocket和HTTP协议的性能比较与选择
websocket·网络协议·http
Aiden_SHU33 分钟前
Wireshark中的length栏位
服务器·网络·wireshark
叫我龙翔1 小时前
【计网】实现reactor反应堆模型 --- 多线程方案优化 ,OTOL方案
linux·运维·网络
群联云防护小杜2 小时前
服务器被挂马怎么办?——解决服务器被挂马的方法和步骤
运维·服务器·网络协议·tcp/ip·安全·ddos
?crying2 小时前
蓝队基础4 -- 安全运营与监控
网络·安全·web安全
ascarl20102 小时前
生成自签名证书并配置 HTTPS 使用自签名证书
网络协议·http·https
茶颜悦色vv2 小时前
蓝队知识浅谈(中)
网络·web安全·网络安全
Xlbb.2 小时前
安全见闻6-9
网络·安全·web安全·网络安全
写bug的小屁孩3 小时前
websocket初始化
服务器·开发语言·网络·c++·websocket·网络协议·qt creator
域智盾系统3 小时前
挖到宝了!统一dlp数据防泄漏解决方案有哪些?千字长文带你熟知这6款!
网络·数据防泄漏·统一dlp数据防泄漏解决方案·数据安全防护措施