JavaEE: 深入探索TCP网络编程的奇妙世界(一)

news/2024/9/24 20:32:42/

文章目录

  • TCP
    • TCP协议段落格式
    • TCP相关机制
      • TCP核心机制一: 确认应答
        • 32位序号
        • 32位确认序号
        • 后发先至问题


TCP

TCP要比UDP更复杂一些~

TCP的全称为"传输控制协议".他负责对数据的传输进行一个详细的控制.

TCP协议段落格式

在这里插入图片描述

  • 源/目的端口号: 表示数据是从哪个进程来.到哪个进程去.

  • 32位序号/32位确认号: 后面再说~

  • 4位首部长度: TCP报头的长度.表示该TCP头部有多少个32bit(有多少个4字节).

    UDP协议报头固定就是8个字节.
    对于TCP来说,它的报头长度是可变长的.(后面再说)

  • 6位标志位:

    • URG: 紧急指针是否有效
    • ACK: 确认号是否有效
    • PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走
    • RST: 对方要求重新建立连接,我们把携带RST标识的称为复位报文段.
    • SYN: 请求建立连接,我们把携带SYN标识的称为同步报文段
    • FIN: 通知对方,本端要关闭了,我们称携带FIN标识的为结束报文字段
  • 16位窗口大小: 后面再说

  • 16位校验和: 发送端填充,CRC校验.接收端校验不通过,则认为数据有问题,此处的校验和不光包含TCP首部,也包含TCP数据部分.

  • 16位紧急指针: 标识哪部分数据是紧急数据.

  • 选项: 40字节头部选项,暂时忽略.

TCP相关机制

TCP最核心的机制,就是"可靠传输".

可靠传输不能做到"100%"送达,只能尽可能的使数据到达对方.

  1. 能感知到对方是否收到
  2. 如果发现对方没收到,就要进行重试.

TCP核心机制一: 确认应答

接收方收到数据之后,就要给发送方返回一个"应答报文"(ack/acknowledge)

TCP引入了序号和确认序号,来使应答报文和传输的数据能够对应上.

由于TCP是面向字节流的,此处的序号不是按照"一条两条"编号,而是按照"字节"进行编号的.
对于一个TCP数据报来说,知道了数据部分的第一个字节序号,就知道了后续所有字节的序号~
序号只是针对TCP数据报携带的载荷来进行编号的.(TCP报头不参与)

32位序号

在这里插入图片描述
32位序号,也就是4个字节,它能表示的范围是0~42亿9千万.也就是0~4GB.
这是否意味着,一个TCP数据报,最大就只能传输4GB呢?

当然不是,首先,TCP进行传输时,一次传输的基本单位不是一个TCP数据报.
不要忘了,TCP是字节流的.
一个TCP数据报,和下一个TCP数据报携带的数据,天然就是可拼接的.

比如要传输一个特别大的数据.
在传输过程中,本身就会通过多个TCP数据报来进行携带.
这些TCP数据报彼此之间携带的载荷都是可以在接收方自动被拼接起来的.

这就不像UDP那样存在传输上限~
使用UDP传输大数据,就要考虑,调用这一次send操作,参数是否超过64kb,超过64kb就不行.

使用TCP的话,就没关系,可以调用一次write,也可以调用多次write(无论怎么进行write,在网络传输和对端接收角度来看都是没差别的)

假设多次write,传输的总数据量,超过上述4GB也没关系,咱们这里的数据序号是可以从0重新设置的.

32位确认序号

在这里插入图片描述

TCP将每个字节的数据都进行了编号,即为序列号.

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

对于应答报文来说,确认序号就会按照收到的数据的最后一个字节的序号+1的方式来填写.

另外,六个标志位中,第二位(ACK),会设为1.

  • 对于普通报文,ack是0
  • 对于应答报文,ack是1

在这里插入图片描述

  • 如果是普通报文,序号是有效的,确认序号是无效的.

  • 如果是ack应答报文,序号和确认序号都是有效的.

    这是另一套编号的体系,和传输数据的序号不是同一套的.

后发先至问题

什么是后发先至?
举个例子,我跟朋友发短信.
在这里插入图片描述

虽然朋友先发的"好啊",后发的"不行,有事",但是网络传输过程中,可能存在"后发先至".
对于我接收方来说,可能先收到"不行,有事"后收到"好啊".
此时歧义就出现了,我认为朋友有事,不能开黑,但是明天可以去北京.而朋友认为能开黑,但是明天有事,不能去北京.

后发先至是客观的情况,无法改变.

为了解决上述问题,TCP就针对接收方收到的数据,进行了重新排序.确保应用程序读取到的数据一定是和发送方的数据顺序是一致的!

更具体一点: A为发送方,B为接收方.
在这里插入图片描述
B接收方这边调用read的时候如果没有数据,就会阻塞等待.
当1001-2000这个数据先到了B时,B不会让read解除阻塞.
直到1-1000这个数据到达之后,read才会解除阻塞,才会读取到1-1000,1001-2000数据.
这样就确保了发送方write顺序和接收方read的顺序始终是保持一致的.

B接收方这边的操作系统内核里,会有一段内存空间,作为"接收缓冲区".
收到的数据,就会先在接收缓冲区中排队等待,直到开头的数据到了,应用程序才能真正读取到里面的数据~

这个过程就跟接亲差不多.
后面的车先到了女方村口,并不能直接开到新娘家门口去接人.
这样的车得在村口等待,必须等头车到了,以及后面的车陆续都差不多,重新排好队,再慢慢开到新娘家门口~

下一篇文章:JavaEE: 深入探索TCP网络编程的奇妙世界(二)

本文到这里就结束啦~
在这里插入图片描述


http://www.ppmy.cn/news/1529954.html

相关文章

仿黑神话悟空跑动-脚下波纹特效(键盘wasd控制走动)

vue使用three.js实现仿黑神话悟空跑动-脚下波纹特效 玩家角色的正面始终朝向鼠标方向&#xff0c;且在按下 W 键时&#xff0c;玩家角色会朝着鼠标方向前进 空格建跳跃 <template><div ref"container" class"container" click"onClick"…

2024最受欢迎的3款|数据库管理和开发|工具

1.SQLynx&#xff08;原SQL Studio&#xff09; 概述&#xff1a; SQLynx是一个原生基于Web的SQL编辑器&#xff0c;由北京麦聪软件有限公司开发。它最初被称为SQL Studio&#xff0c;后改名为SQLynx&#xff0c;支持企业的桌面和Web数据库管理。SQLynx支持所有流行的数据库&a…

PHP纯离线搭建(php 8.1.7)

要离线从零安装 PHP 8.1.7&#xff0c;需要准备好 PHP 的源代码以及所有相关的依赖包。以下是步骤&#xff1a; 步骤概览 在联网系统上下载 PHP 8.1.7 源代码和所有依赖包。 将这些文件传输到离线系统。 安装所需的依赖包。 编译并安装 PHP 8.1.7。 配置 PHP 和 Web 服务器。 …

如何在windows中使用mac,要详细的教程

在 Windows 上运行 macOS 需要使用虚拟机软件。以下是一个详细的教程&#xff0c;展示如何在 Windows 上安装和运行 macOS&#xff1a; 前提条件 硬件要求&#xff1a; 64 位处理器&#xff0c;支持虚拟化技术&#xff08;VT-x 或 AMD-V&#xff09;。至少 8GB 内存&#xff0…

Java-数据结构-优先级队列(堆)-(二) (゚▽゚*)

文本目录&#xff1a; ❄️一、PriorityQueue的常用接口&#xff1a; ➷ 1、PriorityQueue的特性&#xff1a; ➷ 2、使用PriorityQueue的注意&#xff1a; ➷ 3、PriorityQueue的构造&#xff1a; ☞ 1、无参数的构造方法&#xff1a; ☞ 2、有参数的构造方法&#xff1a; …

docker 部署 禅道

拉取镜像 docker pull easysoft/zentao运行 docker run -d --name zentao -e ZT_MYSQL_HOSTxxx -e ZT_MYSQL_PORT3306 -e ZT_MYSQL_USERxxx -e ZT_MYSQL_PASSWORDxxx -e ZT_MYSQL_DBzen_tao_ss -p 80:80 easysoft/zentao注意 配置好mysql连接 参照 https://www.zentao.net…

力扣题解2376

大家好&#xff0c;欢迎来到无限大的频道。 今日继续给大家带来力扣题解。 题目描述&#xff08;困难&#xff09;&#xff1a; 统计特殊整数 如果一个正整数每一个数位都是 互不相同 的&#xff0c;我们称它是 特殊整数 。 给你一个 正 整数 n &#xff0c;请你返回区间 …

Python机器学习基础(NumPy、Pandas、Matplotlib)

Numpy函数库应用 NumPy 是 Python 中用于科学计算的核心库&#xff0c;它提供了高性能的多维数组对象以及用于处理这些数组的工具。 一、创建数组 1.使用array函数从 Python 列表或元组创建数组。 import numpy as np a np.array([1, 2, 3]) print(a) b np.array(…