Linux网络基础--传输层Tcp协议(上) (详细版)

devtools/2024/12/22 20:29:26/

目录

Tcp协议报头:

4位首部长度:

源端口号和目的端口号

32位序号和确认序号

标记位

超时重传机制:

两个问题

连接管理机制

三次握手,四次挥手

建立连接,为什么要有三次握手?

先科普一个概念:SYN洪水:参考博客:[黑客入门] TCP SYN洪水 (SYN Flood) 攻击原理与实现(非常详细)零基础入门到精通,收藏这一篇就够了_tcp syn flood-CSDN博客

正面回答为什么要有三次握手:


Tcp协议报头:

4位首部长度:

首先我们来理解其中最好理解的4位首部长度:

  • 在Tcp协议报头中描述报头长度的长度单位是4字节,总范围为[0,60],单位:字节,也就是说,如果Tcp协议的报头长度为36时,设首部长度 = x,则可以推导出x=9,转换为二进制:1001

done

---------------------------------------------------------------------------------------------------------------------------------

源端口号和目的端口号

可以看看这篇文章:Linux网络基础-----传输层UDP协议-CSDN博客

此处不再赘述;

done

---------------------------------------------------------------------------------------------------------------------------------

32位序号和确认序号

  • 发送方每次发送的请求中,Tcp报头都会携带对应的32位序号,用来表示当前发送的信息的唯一性,同样的,接收方每次做出应答时,应答的Tcp报头中的32位确认序号就是32位序号 + 1,表示当前确认序号之前的数据已经全部收到!

比如说如果确认序号是3001,那么表示3001之前的所有序号的数据都被收到了!

--------------------------------------------------------------------------------------------------------------------------------

标记位

六位

如果应答确认报文:对于Tcp报头,将标记位ACK置为1,序号和确认序号正常比对,即可表示确认报文。

  • 假设发送方先发送了序号为1至1000的数据,接收方成功接收后,会返回一个ACK响应。此时,ACK中携带的确认序号将是1001,表示接收方已经接收到序号为1001之前(即1至1000)的所有数据,并要求发送方从序号1001开始发送下一条数据。
  • 需要注意的是,确认应答的起始序号(即确认序号)并不是固定的1001,而是根据每次发送数据的序列号动态变化的。

----------------------------------------------------------------------------------------------------------------------------

超时重传机制:

        

  • 主机 A 发送数据给 B 之后, 可能因为网络拥堵等一系列原因, 数据无法到达主机 B;
  • 如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答, 就会进行重发;

:假设主机A发了数据给主机B,主机B确实收到了,但是主机B发给主机A的ACK应答,主机A没有收到,在经过一段特定的时间后,主机A会将上一次发送给主机B的数据视为丢包了,会重新再传输一次,直到收到来自主机B的ACK应答再开始下一次新的数据发送。

两个问题

到这里,问题有2个,首先,此时主机B会存在2份一摸一样的数据,主机B是如何对这2份数据去重的呢?答案是:ACK序列号!ACK应答中携带确认序号,告诉接收方“我”收到了多少个字节的数据,通过序列号去重相同的数据字节下标,即可解决数据重复的问题!

第二个问题,特定的时间只多久?是否固定?这个问题也很好解释,首先,重传的时间肯定是和数据传输时的网络状态强相关的,那么这个特定的时间一定是随着网络状态动态变化的,在Linux中中,这个特定的时间初始值为500ms,每丢包一次,这个时间就double一次,直到不再丢包。

----------------------------------------------------------------------------------------------------------------------------

连接管理机制

三次握手,四次挥手

三次握手建立连接,四次挥手断开连接;

先说三次握手,上图:

当Client发起Tcp连接时,会将Tcp报头的标记位的SYN置为1,表示这是一次连接请求,Server收到后,会有一次应答,应答的Tcp报头的标记位的SYN和ACK都置为1,Client收到ACK应答后,自身状态会设置为已连接状态,发送一个ACK应答给Server,Server收到这次ACK之后才会将自己的accept返回,成功建立连接。

那么此处又有问题了:Client最后发送的ACK应答,如果Server没收到这次ACK应答怎么办?

此时,Tcp报头中的标记为又要上场了,RST标记位:Client自身建立好Tcp连接时,如果继续发送消息到Server,但是Server并没有收到Client最后一次的ACK响应,此时,Server会向Client应答一次,这次应答的Tcp报头的标记位中的RST标记位和ACK被置为1,Client收到Server的这次应答后,就知道之前的Tcp连接建立失败了,此时Client会释放异常的连接,重新发起三次握手建立连接

四次挥手:

如果Client的数据全部发送完毕了,在应用层使用了close(fd)释放了文件描述符后,向Server发送断开连接的请求,Tcp报头中的FIN标记位置为1,直到Client收到来自Server的ACK应答之后,Client单方面关闭连接成功,不再给Server发送用户的数据。

如果,Client断开连接后,Server还在处理Client之前发送的历史数据时,依然可以给对应Client发送应答,Client也必须针对这些应答再给Server发送ACK响应(空报文)!

问题又来了,应用层调用close之后,文件读写端不是都会被关闭吗?那么Client该如何拿到Server对历史数据的处理结果呢?

很简单,Linux的shutdown接口,函数原型:

可以对指定的文件描述符,进行指定端的关闭操作,SHUT_RD表示只关闭读端,SHUT_WR表示只关闭写端。这样,Client就能拿到Server的数据了;

建立连接,为什么要有三次握手?

 要正面回答这个问题,首先要阐述一下为什么一次,二次握手不行‘;

先科普一个概念:SYN洪水:参考博客:[黑客入门] TCP SYN洪水 (SYN Flood) 攻击原理与实现(非常详细)零基础入门到精通,收藏这一篇就够了_tcp syn flood-CSDN博客

对于一次握手,二次握手,由于连接比较简单,Clinet可以伪造大量的SYN连接请求,向服务器发起连接请求,一次握手的话,server极有可能会在短时间内被打满相当多的Tcp链接,因为在Server看来,如果只有一次握手,当收到Client的SYN请求时,就默认双方都建立好了Tcp链接

容易让服务器出现严重的问题,甚至挂掉,二次握手同理,Client可以忽略来自Server的应答,继续SYN洪水,还是容易造成上述一次握手的问题。,但是对于三次握手,服务器虽然无法保证能防御SYN洪水,但是比一次,二次握手好一点,至少能保证Clinet一定在自己建立连接成功之前先建立连接成功的状态!

正面回答为什么要有三次握手:

首先,

  • 验证全双工:验证网络的连通性,对于客户端来说,只使用最少的次数验证了双方的连通性,因为能收到服务器的ACK应答;对于服务器来说,也只用了最少的次数验证了双方的连通性,因为同理能收到来自客户端的ACK应答
  • 建立双方通信的共识意愿,客户端先发出SYN连接请求,服务器收到了,返回一个ACK应答,至此,客户端建立连接结束,但是Tcp连接是全双工的,服务器也要向客户端发送连接请求SYN,得到客户端的ACK应答后,即完成三次握手,而在其中服务器向客户端发送第一次ACK时会捎带SYN,即捎带应答;

----------------------------------------------------------------------------------------------------------------------------

TODO


http://www.ppmy.cn/devtools/144467.html

相关文章

ubuntu22.04编译安装Opencv4.8.0+Opencv-contrib4.8.0教程

本章教程,主要记录在Ubuntu22.04版本系统上编译安装安装Opencv4.8.0+Opencv-contrib4.8.0的具体过程。 一、下载opencv和opencv-contrib包 wget https://github.com/opencv/opencv/archive/refs/tags/4.8.0.zip wget https://github.com/opencv/opencv_contrib/archive/refs/…

雅思真题短语梳理(四)

61方面 which aspects of the story 62变化 alter least 63更重要 more central / more important 64人物 the characters in it 65伪装 in disguise 66琐碎的 trivial details 67代代相传 reproduced from generation to generation 68嗜血、阴森的一面 blood-thirsty and gru…

相机与NAS的奇妙组合,如何使用相机拍照自动上传或备份到NAS

相机与NAS的奇妙组合,如何使用相机拍照自动上传或备份到NAS 哈喽小伙伴们好,我是Stark-C~ 对于喜欢使用专业器材拍照摄影的小伙伴来说,想要将相机存储卡中的照片或视频导出到电脑上,要么是使用数据线直接和相机连接,…

Java 单元测试中 JSON 相关的测试案例

Java 单元测试中 JSON 相关的测试案例 在 Java 单元测试中,处理 JSON 数据的场景非常常见,通常包括生成 JSON 数据、解析 JSON 数据,以及验证其内容是否符合预期。以下详细讲解相关的测试用例、工具和实现方法。 1. 常用 JSON 库 在 Java 中…

Redis List操作

Redis List操作 1、lPush 在名称为key的list左边(头)添加一个值为value的 元素 $redis->lPush(key, value);2、rPush 在名称为key的list右边(尾)添加一个值为value的 元素 $redis->rPush(key, value);3、lPushx/rPushx 在名…

前端数据持久化指南:LocalStorage、SessionStorage 等的区别与应用

一、引言 在前端开发中,数据持久化是一个至关重要的需求。它能够确保用户在不同页面切换、刷新页面或者关闭浏览器后,数据仍然能够被保存和恢复。本文将详细介绍几种实现前端数据持久化的方法,并深入分析它们之间的区别。 二、实现前端数据…

C# OpenCV机器视觉:图像分割(让照片中的物体各自“安家”!)

在一个无聊的周末,阿强决定去参加一个朋友的聚会。他兴奋地准备好相机,想要记录下这次难忘的时刻。然而,当他查看自己拍的照片时,发现每张照片都像是一幅混乱的拼图,物体之间的界限模糊不清,仿佛所有的东西…

java中带缓存的输入/输出流

1、介绍 缓存时I/O的一种性能优化。缓存流为I/O流增加了内存缓存区。有了缓存区,使得在流上执行skip()、mark()、reset()方法都成为可能。 2、BufferedInputStream与BufferedOutputStream类 BufferedInputStream类可以对所有InputStream类进行带缓存区的包装以达…