TCP中三个函数与三次握手的关系?

发布网友 发布时间:2022-04-24 01:49

我来回答

3个回答

热心网友 时间:2023-10-03 05:40

TCP是属于网络分层中的传输层,因为OSI分为7层,感觉太麻烦了,所以分为四层就好了,简单。
分层以及每层的协议,TCP是属于传输层,如下两张图:

TCP三次握手会涉及到状态转换所以这里贴出TCP的状态转换图如下:

TCP三次握手简述
TCP三次握手如图:

第一次握手
客户主动(active open)去connect服务器,并且发送SYN 假设序列号为J,
服务器是被动打开(passive open)

第二次握手
服务器在收到SYN后,它会发送一个SYN以及一个ACK(应答)给客户,
ACK的序列号是 J+1表示是给SYN J的应答,新发送的SYN K 序列号是K

第三次握手
客户在收到新SYN K, ACK J+1 后,也回应ACK K+1 以表示收到了,
然后两边就可以开始数据发送数据了

使用tcpmp观察如下:因为都是在本机同时运行client和server所以命令为:tcpmp -i lo port 5555, 只能监听回路lo接口,结果如下

如图用红色圈起来的就是3次握手,但是为什么最后一次握手,为什么ack = 1,而不是369535922 呢,
这是因为这里的第三次握手tcpmp显示的是相对的顺序号。但是为了便于观察我们需要把tcpmp的
顺序号变为绝对的顺序号。

命令只需要加-S(大写)便可,即:tcpmp -i lo port 5555 -S
加上之后结果就正常了如下图:

从tcpmp的数据,可以明显的看到三次握手的过程是:
第一次握手:client syn 2322326583 —> server
第二次握手:server syn 3573692787, ack 2322326583 + 1 —> client
第三次握手:client ack 3573692787 + 1 -->server

TCP三次握手详细解析过程:

第一次握手
客户在socket() connect()后主动(active open)连接上服务器, 发送SYN ,这时客户端的状态是SYN_SENT
服务器在进行socket(),bind(),listen()后等待客户的连接,收到客户端的 SYN 后,

1.半连接队列(syn queue)未满
服务器将该连接的状态变为SYN_RCVD, 服务器把连接信息放到半连接队列(syn queue)里面。

2.半连接队列(syn queue)已满
服务器不会将该连接的状态变为SYN_RCVD,且将该连接丢弃(SYN flood攻击就是利用这个原理,
对于SYN foold攻击,应对方法之一是使syncookies生效,将其值置1即可,路径/proc/sys/net/ipv4/tcp_syncookies,
即使是半连接队列syn queue已经满了,也可以接收正常的非恶意攻击的客户端的请求,
但是这种方法只在无计可施的情况下使用,man tcp里面的解析是这样说的,

但是我不知道为什么Centos6.9默认是置为1,所以这让我很疑惑
)。
半连接队列(syn queue)最大值 /proc/sys/net/ipv4/tcp_max_syn_backlog

SYN flood攻击

攻击方的客户端只发送SYN分节给服务器,然后对服务器发回来的SYN+ACK什么也不做,直接忽略掉,
不发送ACK给服务器;这样就可以占据着服务器的半连接队列的资源,导致正常的客户端连接无法连接上服务器。-----[维基百科]

(SYN flood攻击的方式其实也分两种,第一种,攻击方的客户端一直发送SYN,对于服务器回应的SYN+ACK什么也不做,不回应ACK, 第二种,攻击方的客户端发送SYN时,将源IP改为一个虚假的IP, 然后服务器将SYN+ACK发送到虚假的IP, 这样当然永远也得不到ACK的回应。)

第二次握手
服务器返回SYN+ACK给到客户端,客户端收到SYN+ACK后,状态从SYN_SENT变为ESTABLISHED,
也即是connect()函数的返回。

第三次握手
全连接队列(accept queue)的最大值 /proc/sys/net/core/somaxconn (默认128)

全连接队列值 = min(backlog, somaxconn)
这里的backlog是listen(int sockfd, int backlog)函数里面的那个参数backlog

1.全连接队列(accept queue)未满
服务器收到客户端发来的ACK, 服务端该连接的状态从SYN_RCVD变为ESTABLISHED,
然后服务器将该连接从半连接队列(syn queue)里面移除,且将该连接的信息放到全连接队列(accept queue)里面。

2.全连接队列(accept queue)已满
服务器收到客户端发来的ACK, 不会将该连接的状态从SYN_RCVD变为ESTABLISHED。
当然全连接队列(accept queue)已满时,则根据 tcp_abort_on_overflow 的值来执行相应动作
/proc/sys/net/ipv4/tcp_abort_on_overflow 查看参数值

2.1 tcp_abort_on_overflow = 0
则服务器建立该连接的定时器,

这个定时器是一个服务器的规则是从新发送syn+ack的时间间隔成倍的增加,
比如从新了第二次握手,进行了5次,这五次的时间分别是 1s, 2s,4s,8s,16s,
这种倍数规则叫“二进制指数退让”(binary exponential backoff)

给客户端定时从新发回SYN+ACK即从新进行第二次握手,(如果客户端设定的超时时间比较短就很容易出现异常)
服务器从新进行第二次握手的次数/proc/sys/net/ipv4/tcp_synack_retries

2.2 tcp_abort_on_overflow = 1
关于tcp_abort_on_overflow的解析如下:

意思应该是,当 tcp_abort_on_overflow 等于1 时,重置连接(一般是发送RST给客户端),
至于怎么重置连接是系统的事情了。
不过我在查资料的过程发现,阿里中间件团队博客说并不是发送RST, —[阿里中间件团队博客]

这个博客跑的实例观察到的是服务器会忽略client传过来的包,然后client重传,一定次数后client认为异常,然后断开连接。
当然,我们写代码的都知道代码是第一手的注释,实践是检验真理的唯一标准,
最好还是自己以自己实践为准,因为可能你的环境跟别人的不一样。)

查看全连接队列(accept queue)的使用情况

如上图,第二列Recv-Q是,全连接队列接收到达的连接,第三列是Send-Q全连接队列的所能容纳最大值,
如果,Recv-Q 大于 Send-Q 那么大于的那部分,是要溢出的即要被丢弃overflow掉的。

感想:
1.本来想写TCP连接的建立和终止的,没想到要讲清楚TCP连接的建立已经很大的篇幅了,就只讲TCP连接的建立而已。
2.以前看书的时候,没有解决一个问题的来的深刻或者说脉络清晰,这个就是主题阅读的好处吧。
3.以前没有养成一个遇到问题深入解析,解决问题的习惯,今后慢慢养成。

下面的参考1有实例,会比较详细一点,清晰一些。
参考:

http://jm.taobao.org/2017/05/25/525-1/
https://coolshell.cn/articles/115.html
https://zh.wikipedia.org/wiki/SYN_cookie
https://zh.wikipedia.org/wiki/SYN_flood
https://www.cnblogs.com/menghuanbiao/p/5212131.html
————————————————
版权声明:本文为CSDN博主「jun20125」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jun20125/article/details/81506353

热心网友 时间:2023-10-03 05:40

这是你创建的套接字类型决定的,常用的套接字是数据流类型(TCP)和数据报文类型(UDP),创建这些类型的套接字的时候就已经带上了相应的协议栈,这些握手信息在协议栈内部就已经实现了,不需要上层应用去实现
如果你想自己去控制握手信息,需要创建原始套接字,这种类型的套接字是基于IP层的,很多抓包工具就是通过这种类型的套接字来实现的,在这一层上你就可以自己定义处理握手信息,但这样相当于你要自己来实现TCP协议栈了,这难度太高,而且一般情况下也没必要
如果只是对握手的过程感兴趣,安装一个抓包工具观察一下连接的时候C/S之间的通信数据包就可以了

热心网友 时间:2023-10-03 05:41

TCP需要三次握手才能建立连接,那么为什么需要三次握手呢?

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com