JavaEE 初阶篇-深入了解网络原理 TCP/IP 协议

news2024/10/5 15:33:13

🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍

文章目录

        1.0 TCP 协议概述

        1.1 TCP 协议格式

        2.0 TCP 协议的特性

        2.1 确认应答

        2.2 超时重传

        2.2.1 超时的时间如何确定?

        2.3 连接管理

        2.3.1 三次握手

        2.3.2 四次挥手

        2.3.3 为什么是 TIME_WAIT 的时间是 2 MSL ?

        2.3.4 服务器出现大量的 CLOSE_WAIT 是什么导致的?

        2.4 滑动窗口

        2.4.1 遇到丢包情况该 TCP 该如何进行重传?

        2.5 流量控制

        2.6 拥塞控制

        2.7 延迟应答

        2.7.1 所有的包都可以延迟应答吗?

        2.8 捎带应答

        2.9 粘包问题

        2.9.1 如何避免粘包问题呢?

        2.9.2 UDP 会存在粘包问题吗?

        2.10 异常情况


        1.0 TCP 协议概述

        TCP 协议在传输层,TCP 是传输层协议的一种,传输层中的协议不单单只有 TCP 或者 UDP 。当应用层将数据打包后交给传输层时,如果选择使用 TCP 协议,传输层会在数据包上加上 TCP 报头;如果选择使用 UDP 协议,传输层会在数据包上加上 UDP 报头。

        1.1 TCP 协议格式

        1)源端口号:表示数据从哪个应用程序发送出来。

        2)目的端口号:表示数据要发送到哪个目的应用程序中。

        3)32 位序号:TCP 协议中的序号是记录字节流中第一个字节的编号。每个 TCP 报文段都有一个序号字段,用来标识该报文段中第一个字节在整个字节流中的位置。接收端根据序号对接收到的数据进行排序和重组,确保数据的有序传输和可靠性。

        简单来说,发送方会对发送的每一个字节进行排序编号,一个字节一个编号。比如,发送从编号为 1 到编号为 1000 的字节,那么此时的 TCP 报头序号中就会记录编号 1 。

        4)32 位确认序号:当接收方接收到了 TCP 的数据包,那么就会响应一个确认序号。比如,发送方:发送从编号为 1 到编号为 1000 的字节。接收方接收:该数据包之后,会给发送方一个响应 1001 ,所以该响应的序号就是确认序号。

        总结一下,确认序号是指下一个期望接收的字节序号,用来告知发送方接收方已经成功接收到的数据包的序号。

        5)4 位头部长度:又称为 4位 TCP 报头长度,表示该 TCP 头部有多少个 32 位 bit (有多少个 4 字节),所以 TCP 头部最大长度是 15 * 4 = 60 个字节长度。

        6)6 位保留:保留的是头部长度,所以以后 TCP 所需要的报头不够时,那么就可以从保留的空间中给报头长度进行扩展,不过保留的最大只有 6 个 bit 。

        7)6 位标志位

        URG:紧急指针是否有效。

        ACK:确认号是否有效,当接收方接收到数据时,就会发送 ACK 信号进行响应。

        PSH:提示接收端应用程序立刻从 TCP 缓冲区把数据读走,接收方中会有一个容器进行存储数据,该容器相当于是一个优先级阻塞队列(缓冲区)。

        PST:对方要求重新建立连接,我们把携带 RST 标识的称为复位报文段。

        SYN:请求建立连接。

        FIN:请求断开连接。

        8)16 位窗口大小:发送方根据接收方返回的窗口大小来控制发送数据的速度,以避免发送过多数据导致网络拥塞。如果接收方的窗口大小为0,发送方将停止发送数据,直到接收方的窗口大小变为大于0为止。可以实现流量控制和拥塞控制,从而保证数据传输的可靠性和效率。

        9)16 位校验和:发送方填充,CRC 校验,接收方进行校验,若校验不通过,则认为数据有问题。此处校验和不光包含 TCP 首部,也包含 TCP 数据部分。

        10)16 位紧急指针:标识哪部分是紧急数据。

        2.0 TCP 协议的特性

        TCP 重要的特性:确认应答、超时重传、连接管理、滑动窗口、流量控制、拥塞控制、延迟应答、捎带应答、粘包、异常情况等特性来确保 TCP 可靠性和高的性能。

        2.1 确认应答

        接收方在接收到数据包后会发送确认应答给发送方,确保发送方知道数据包已经成功到达。通过 TCP 报头中的序号和确认序号来实现该机制,当发送方发送的字节,报头中会记录第一个字节的序号,当接收方接收到该数据时,会给发送方响应一个确认序号。表示:接收方已经接收到了数据了,期待下一个数据,下一个数据从第几个字节开始。

        简单来说:每一个 ACK 都带有对应的确认序号,意思是告诉发送者,我已经收到了哪些数据;下一次你从哪里开始发。

如图:

        2.2 超时重传

        当主机 A 发送数据,一段时间后,没有接收到主机 B 的响应,就会触发超时重传。

        分两种情况:

        1)主机 A 发送的数据,因为某个原因导致在中间丢包了,那么这种情况,确实要通过超时重传:主机 A 重新发送数据到主机 B 中。这种情况没有太大问题。

        2)主机 A 发送的数据,主机 B 接收到了,当主机 B 发送 ACK 进行响应,那么 ACK 因某个原因导致丢包了,那么主机 A 过一段时间,没有接收到响应,就会触发超时重传,这可能就会有问题了,本来主机 B 已经接收到了数据,主机 A 触发了超时重传,又继续给主机 B 发送相同的数据。

        因此主机 B 会收到很多重复数据,那么 TCP 协议需要能够识别出哪些包是重复的包,并且把重复的丢弃掉,这时候我们可以利用前面提到的序列号,就可以很容易做到去重的效果。

        2.2.1 超时的时间如何确定?

        最理想的情况下,找到一个最小的时间,保证“确认应答一定能在这个时间内返回”,但是这个时间的长短,随着网络环境的不同,是有差异的。

        如果超时时间太长,会影响整体的重传效率;

        如果超时时间太短,有可能会频繁发送重复的包;

        因此 TCP 为了保证无论在任何环境下都能比较高性能的通信,会动态计算这个最大超时时间。累计到一定的重传次数, TCP 认为网络或者对端主机出现异常,强制关闭连接。

        2.3 连接管理

        正常情况下:TCP 通过三次握手建立连接、通过四次挥手断开连接。

        2.3.1 三次握手

        具体流程:

        主机 A 要想跟主机 B 建立连接,首先主机 A 会发送带有 SYN 信号的 TCP 给到主机 B ,来请求建立连接。seq 是序列号,发送的数据的第一个字节序号为 x 。当主机 A 发送完请求连接时,处于 SYNSENT 状态,该状态表示:等待响应。

        此时主机 B 正在出于监听状态,监听来自客户端的连接请求。所以 LISTEN 状态通常是服务器在等待客户端连接时的初始状态。

        当主机 B 接收到主机 A 发送的请求连接信息时,主机 B 会响应带有 ACK 信号的 TCP ,代表已经接收到数据了,确认学号 ack 为 x + 1,表示期待接收下一个数据为:x + 1,同时还带有 SYN ,表示主机 B 请求与主机  A 建立连接。当主机 B 发送完 SYN ,处于 SYNRCVD 状态,该状态表示:服务器已经接收到客户端发送的 SYN 包,并已经发送了自己的 SYN 包作为响应,表示同意建立连接。

        当主机 A 接收到了主机 B 发送的 TCP 包时,会发送一个带有 ACK 信号的 TCP,表示:已经接收到数据了,seq 序列号:记录发送数据中的第一个字节序号为 x + 1。

        最后,双方就成功建立了连接,都处于 ESTABLISHED 状态。在 ESTABLISHED 状态下,双方可以互相发送数据,进行通信和交换信息。

建立连接的意义:

        1)投石问路,确认当前通信路径是否通畅。

        2)确保双方都具备接收数据的能力。

        3)协商参数,通信双方共同确认一些通信中的必备参数数值,比如协商序列号。

        2.3.2 四次挥手

        具体流程:

        客户端想要断开与服务器的连接,首先,客户端会发送带有 FIN 信号的 TCP 包给服务器。

        服务器先会响应带有 ACK 信号的 TCP 包给客户端,表示:服务器已经接收到数据了。此时服务器可能还没有接收完数据,需要继续接收数据,还不能断开连接。服务端此时处于 CLOSEWAIT 状态。等待数据接收完毕了,手动调用 close() 方法,服务端会主动发送带有 FIN 信号的 TCP 给客户端。

        最后客户端接收到服务端发送的 TCP 包后,就代表着可以正式断开连接了,因此客户端发送带有 ACK 信号的 TCP ,服务端此时处于 LASTACK 状态,接收最后一个 ACK 信号。当服务端接收完毕之后,就会处于 CLOSE 状态,服务端就成功断开连接了。

        对于客户端来说还需要等待 2MSL ,而不是立马像服务端直接结束。这是因为,万一客户端发送的 ACK 在中间丢包了,就需要触发超时重传,所以需要等待一段时间,来确保 ACK 成功发送到服务器中。

        2.3.3 为什么是 TIME_WAIT 的时间是 2 MSL ?

        1)MSL 是 TCP 报文的最大生存时间,因此 TIME_WAIT 持续存在 2 MSL 的话,就能保证在两个传输方向上的尚未接收或者迟到的报文都已经消息。 

        2)也是理论上保证最后一个报文可靠到达(假设最后一个 ACK 丢失,那么服务器会再重发一个 FIN ,这时虽然客户端的进程不在了,但是 TCP 连接还在,仍然可以重发 LAST_ACK)

        2.3.4 服务器出现大量的 CLOSE_WAIT 是什么导致的?

        一般而言,对于服务器上出现大量的 CLOSE_WAIT 状态,原因就是服务器没有正确的关闭 socket.close() ,导致四次挥手没有正确完成,这是一个 BUG ,只需要加上 close 即可解决问题。 

        2.4 滑动窗口

        对于每一个发送的数据段,都要给一个 ACK 确认应答,收到 ACK 后再发送下一个数据,这样做有一个比较大的缺点,即使性能较差,尤其是数据往返的时间较长的时候。

        对于这种情况,就引入了滑动窗口。TCP 报头上的窗口大小值的是,无需等待确认应答而可以继续发送数据的最大值。

举个例子:

        窗口大小为 4 ,发送前四个数据的时候,不需要等待任何 ACK ,直接发送;收到第一个 ACK 后,滑动窗口向后移动,继续发送第五个数据;依此类推;

        这样就有效提高效率了,当发送数据的时候,同时也等待着下一个 ACK 。当速度够快时,看起来就像一下子移动 4 格。

        操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录还有哪些数据没有应答;只有确认应答过的数据,才能从缓冲区删掉。

        窗口越大,则网络的吞吐率就越高。

        2.4.1 遇到丢包情况该 TCP 该如何进行重传?

        这里分两种情况进行讨论。

        1)数据包已经抵达,只是 ACK 被丢失了。

        这种情况下,部分 ACK 丢了并不要紧,因为可以通过后序的 ACK 进行确认。因为只要后序的 ACK 返回了,就代表着前面的数据包都接收完毕了,只是 ACK 丢了仅此而已。

        2)出现数据包丢了的情况。

        当某一段数据丢失之后,发送端会一直收到 1001 这样的 ACK ,就像在提醒发送端“我想要的是 1001 一样”;

        如果发送端主机连续三次接收到 1001 这样的应答,那么发送端就会在缓冲区中拿到相应的数据重新发送。

        这个时候接收端收到 1001 之后,再次返回的 ACK 就是 7001 了,接收端其实之前就已经接收到,被放到接收缓冲区中;这种机制被称为“高速重发控制”(也叫“快重发”)。

        2.5 流量控制

        接收端处理数据的速度是有限的,如果发送端发的太快,导致接收端的缓冲区被打满,这时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应。

        因此 TCP 支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制。

        接收端将自己可以接收的缓冲区大小放入 TCP 首部中的“窗口大小”字段,通过 ACK 端通知发送端。窗口大小字段越大,说明网络的吞吐量越高。接收端一旦发现自己的缓冲区快满了,将会将窗口大小设置成一个更小的值通知给发送端。发送端接收到这个窗口之后,就会减慢自己的发送速度。如果接收端缓冲区满了,就会将窗口置为 0,这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端。

        2.6 拥塞控制

        TCP 引入慢启动机制,先发送少量的数据,探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传输数据。

        一开始的时候会慢启动,窗口大小一般从 1 开始往上增加,这是因为刚开始发送数据时,不清楚具体的网络环境状况,则窗口需要根据实际的网络情况来增加。一开始,发送方每接收到一个 ACK ,窗口就会 +1 ,指数式增长,到一定的阈值之后,按照线形方式增长。

        1)TCP Reno 版本

        一开始的阈值为 16 ,超过这个数值,就会以线性方式继续增长,当收到 3 个重复 ACK 执行快重传时,说明此时网络拥塞,那么就需要将窗口大小就会恢复到拥塞的一半 12 。继续以线性的方法继续增长。依次类推,最后会达到一个稳定的窗口大小情况。

        2)TCP Tahoe 版本

        当接收到多个快重传时,首先窗口会重新从 1 开始往上增加,没接收到一个 ACK 就会窗口大小 +1 ,且阈值变成拥塞时窗口大小的一半。当窗口大小增加到 12 前,以指数方式增长,一旦超过 12 ,以线性方法继续增长,以此类推。

        每次发送数据包的时候,将拥塞窗口和接收端主机反馈的窗口大小做比较,取较小的值作为实际发送的窗口。

        2.7 延迟应答

        在TCP通信中,接收端收到数据后会发送确认应答,确认已经接收到数据。如果接收端立即发送确认应答,那么发送端会根据确认应答的窗口大小来继续发送数据。如果确认应答的窗口大小比较小,发送端发送的数据量就会受限,影响了传输效率。

        而如果接收端延迟发送确认应答,等待一段时间后再发送,那么确认应答的窗口大小可能会更大。这样一来,发送端可以发送更多的数据,提高了网络传输效率。因为窗口越大,发送端就可以发送更多的数据,从而提高了网络吞吐量。

        发送窗口大小受到接收方的缓冲区剩余大小和延迟应答策略的双重影响。接收方的缓冲区大小决定了最大的发送窗口大小,而延迟应答可以在这个范围内动态调整确认应答的窗口大小。

        2.7.1 所有的包都可以延迟应答吗?

        肯定不是。

        1)数量限制:每隔 N 个包就应答一次。一般 N 取 2 。

        2)时间限制:超过最大延迟时间就应答一次。超时间取 200 ms 。

        2.8 捎带应答

        捎带应答是指在发送 TCP 报文时,如果接收方正好有数据要发送给发送方,那么可以将这些数据捎带在 TCP 报文的 ACK(确认)中一起发送,而不需要额外发送一个单独的数据包。

        这种捎带应答的机制可以提高网络的利用率和效率,减少网络传输时延。当接收方收到数据后,如果刚好有数据要发送给发送方,可以直接在 ACK 中回复,并携带需要发送的数据,这样可以减少网络传输的次数,提高网络的吞吐量。

        需要注意的是,捎带应答只能在 TCP 中使用,而且只能在接收方发送 ACK 时才能进行,发送方不能在发送数据时捎带应答。

        2.9 粘包问题

        首先明确,粘包问题中的“包”,是指的应用层的数据包。在 TCP 的协议头中,没有如同 UDP 一样的“报文长度”这样的字段,但是有一个序号这样的字段。

        站在传输层的角度,TCP 是一个一个报文过来的,按照序号排好放在缓冲区中。

        站在应用层的角度,看到的只是一串连续的字节数据。

        那么应用程序看到了这么一连串的字节数据,就不知道从哪个部分开始到哪个部分,是一个完整的应用层数据包。

        2.9.1 如何避免粘包问题呢?

        归根结底就是一句话,明确两个包之间的边界。

        对于定长的包,保证每次都按固定大小读取即可。

        对于变长的包,可以在报头位置,约定一个包总长度的字段,从而就知道了包的结束位置。

        对于边长的包,还可以在包和包之间使用明确的分隔符。

        2.9.2 UDP 会存在粘包问题吗?

        UDP 是一种无连接的传输协议,不会对数据包进行拆分和合并,因此不存在 TCP 中的粘包问题。每个 UDP 数据包都是独立的,不会因为传输过程中被合并或拆分而导致粘包问题。

        2.10 异常情况

        1)进程终止:进程终止会释放文件描述符,操作系统仍然可以发送 FIN ,和正常关闭没有什么区别。当一个端口上的所有数据都发送完毕后,操作系统会自动发送一个 FIN 段,用来通知另一端数据发送完毕并准备关闭连接。

        2)机器重启:和进程终止的情况相同。

        3)机器掉电/网络断开:接收端认为连接还在,一旦接收端有写入操作,接收端发现连接已经不在了,就会进行 RESET ,即使没有写入操作,TCP 自己也会内置一个保活定时器,会定期询问对方是否还在,如果对方不在,也会把连接释放。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1677004.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

win11配置MongoDB6详情记录

一.电脑配置 如下~ 二.下载MangoDB 1.官网download:Download MongoDB Community Server | MongoDBhttps://www.mongodb.com/try/download/community 2.开始安装 自定义安装位置!!! (有一个要不要安装compass的选项&am…

C语言如何在链表中的指定位置插⼊结点?

一、问题 在链表中的指定位置插⼊⼀个结点,要求链表本身必须已按某种规律排好序。如何在链表中的指定位置插⼊新结点,需要掌握怎样找到插⼊的位置以及怎样实现插⼊? 二、解答 由于链表是链式结构的,因此要插⼊⼀个结点&#xff0…

防火墙技术的演进,什么是下一代防火墙(NGFW)?

防火墙技术的演进 防火墙技术的演进经历了不同阶段,从包过滤防火墙到状态检测防火墙,再到集成多种安全功能的UTM(统一威胁管理)设备,最终发展到具备应用识别能力的NGFW(下一代防火墙)。 包过滤…

随笔:贝特弹琴

半年前,我买了一架朗朗代言的智能电子琴。所谓智能是指,它配套的手机软件知道你在按哪个键,它还能让任意按键发光。用专业术语说,它的键盘具有输入和输出功能,和软件组合起来是一个完整的计算机系统。 随着软件练习曲…

运维别卷系列 - 云原生监控平台 之 03.prometheus label 实践

文章目录 [toc]label 简介自定义标签relabel_configsregexrelabel_action metric_relabel_configs两者的区别 实践 label 简介 label 对于 Prometheus 来说,属于数据处理的方式,Prometheus 是通过指定的 label 来查询数据 Prometheus 的 target 中实例&…

LeetCode算法题:128. 最长连续序列

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1: 输入:nums [100,4,200,1,3,2] 输出:4 …

pnpm:无法加载文件 C:\Users\PC\AppData\Roaming\npm\pnpm.ps1,因为在此系统上禁止运行脚本。

使用pnpm命令启动vue时报了个错: 解决起来也简单,右击开始菜单,用管理员身份打开终端。win11的如下图: win10我记得应该是PowerShell(管理员),这样的。 打开之后执行命令: set-…

二维数组经典题型---环形数组和蛇形矩阵(Java)

文章目录 前言1.环形数组1.1.题目1.2.题目分析1.3.代码展示1.4.不足 2.[蛇形矩阵](https://ac.nowcoder.com/acm/problem/22231)2.1.题目2.2.题目分析2.3.代码展示 总结 前言 每日一题—第四届上海理工大学程序设计全国挑战赛 —环形数组 1.环形数组 1.1.题目 这道题跟牛客网…

HTML静态网页成品作业(HTML+CSS)——动漫喜羊羊网页设计制作(4个页面)

🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有4个页面。 二、作品演示 三、代…

​​​【收录 Hello 算法】6.2 哈希冲突

目录 6.2 哈希冲突 6.2.1 链式地址 6.2.2 开放寻址 1. 线性探测 2. 平方探测 3. 多次哈希 6.2.3 编程语言的选择 6.2 哈希冲突 上一节提到,通常情况下哈希函数的输入空间远大于输出空间,因此理论上哈希冲突是不可避免的。比如&a…

2、快速搭建Vue框架以及项目工程

本篇文章详细讲解在配置完vue2环境后如何快速搭建一个Vue框架和项目工程。(以智慧农业云平台为例) 2.1 Vue工程创建 2.1.1创建想要存放的Vue文件夹 找到想要存放的文件夹并在目录搜索框中,并用管理员的方式打开。 2.1.2创建Vue工程 2、安装…

UStaticMesh几何数据相关(UE5.2)

UStaticMesh相关类图 UStaticMesh的数据构成 UStaticMesh的FStaticMeshSourceModel UStaticMesh的Mesh几何元数据来自于FStaticMeshSourceModel, 一级Lod就存在一个FStaticMeshSourceModel. FStaticMeshSourceModel几何数据大致包含以下几类: Vertex(点), VertexI…

【源码】Spring Data JPA原理解析之Repository的自动注入(一)

Spring Data JPA系列 1、SpringBoot集成JPA及基本使用 2、Spring Data JPA Criteria查询、部分字段查询 3、Spring Data JPA数据批量插入、批量更新真的用对了吗 4、Spring Data JPA的一对一、LazyInitializationException异常、一对多、多对多操作 5、Spring Data JPA自定…

4种现象表明你的血糖控制良好!

如果你出现以下4种现象,恭喜你,说明你的血糖控制的不错,需要继续坚持。 1.饥饿感减少,我们的脏腑能够吸收血液中的糖分了,就用不着饿了。,血液中的糖能够得到充分的利用,血糖自然降下去。 2.体…

找到字符串中所有字母异位词 ---- 滑动窗口

题目链接 题目: 分析: 要找的是在s中和p是异位词的子串, 也就是说子串大小和p相同, 那么就是窗口大小固定的滑动窗口问题可以使用哈希数组来记录每个元素出现的个数, 定义hash1存放p中的各元素个数定义left 0; right 0;进窗口 让right指向的元素进窗口, 即更新hash2中的元素…

vue3自定义指令​(通过指令钩子获得dom和钩子参数)

实现文本框自动获得焦点 Index.vue: <script setup> import { ref, onMounted } from vue import ./index.cssconst vFocus {mounted: (el, binding) > {el.focus()console.log(binding)} }onMounted(() > {}) </script><template><div class&qu…

C#委托以及在事件驱动编程中的使用

C#中的委托&#xff08;Delegate&#xff09;是一种类型&#xff0c;它可以存储对方法的引用&#xff0c;并且可以像其他类型一样传递给方法。委托提供了一种灵活的方式来实现事件处理、回调函数和多播委托等功能。以下是关于C#委托的详细介绍&#xff1a; 定义&#xff1a; …

量化研究---A股赚钱日历,上证指数为例,提供源代码

今天把A股的全部数据导出做了一些赚钱日历分析&#xff0c;看那个月赚钱容易&#xff0c;那个月赚钱困难 导入需要的库 import pandas as pdimport matplotlib.pyplot as pltimport quantstats as qsfrom trader_tool.index_data import index_datafrom trader_tool import j…

风电功率预测 | 基于BP神经网络的风电功率预测(附matlab完整源码)

风电功率预测 风电功率预测 | 基于BP神经网络的风电功率预测(附matlab完整源码)完整代码风电功率预测 | 基于BP神经网络的风电功率预测(附matlab完整源码) 基于BP神经网络的风电功率预测是一种常见的方法,它利用BP神经网络模型来预测风电场的发电功率。下面是一个基于BP神经…

HTML常用标签-表格标签

表格标签 1 常规表格2 单元格跨行3 单元格跨行 1 常规表格 table标签 代表表格 thead标签 代表表头 可以省略不写 tbody标签 代表表体 可以省略不写 tfoot标签 代表表尾 可以省略不写 tr标签 代表一行 td标签 代表行内的一格 th标签 自带加粗和居中效果的td 代码 <h…