JavaEE-轻松了解网络原理之TCP协议

TCP协议

TCP,即Transmission Control Protocol,传输控制协议.

TCP协议数据格式

在这里插入图片描述

  • 16位源端口号与16位目的端口号表示数据从那个进程来要到那个进程去.
  • 32位序号表示一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号(TCP将每个字节的数据都进行了编号,称为序列号).
  • 32为确认序号表示接收方对发送的tcp报文段的响应。 其值是收到的TCP报文段的序号值加1.
  • 4位TCP报文长度表示该TCP头部有多少个32位bit(有多少个4字节),所以TCP头部最大长度是15 * 4 = 60字节.

6位标志位:
URG:表示紧急指针是否有效
ACK:确认号是否有效
PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走
RST:表示复位连接,也就是重新建立连接
SYN:表示同步,把携带SYN标识的称为同步报文
FIN:通知对方,本端要关闭了,我们称携带FIN标识的为结束报文段

  • 16位窗口大小:表示接收端TCP 能最大提供65535个字节的缓冲.
  • 16位校验和:发送方通过以TCP报头与报文数据进行一定数学计算得到的结果填充于此,接收方以相同数学方法进行计算,如果校验和相同则校验成功.
  • 16位紧急指针:标识哪部分数据是紧急数据.

TCP原理

确认应答

接收到发送方的数据后,会返回发送一个带有接收数据的最后一个字节的下一个字节序号的ACK报文.

比如接收到的最后一个字节序号为1000,则返回的序号为1001,代表前1000个字节数据已经全部收到.

为解决后发先至,tcp会有一个接收缓冲区(内核中的内存空间),每个socket都有一份自己的接受缓冲区,tcp可在缓冲区对收到的消息根据序列号进行整队.

超时重传

网络传输可能会出现丢包的情况:

  1. 发送的数据报接受方没有收到
  2. 接受方收到后,发回的ack报文传输过程中丢失.

应对策略
发送方没有收到ack应答报文,就会隔一段时间进行报文重发,随着重发次数的增加,间隔时间也会增长,连续多次重传后还是无法获取ack报文,此时tcp就会尝试重置连接,如果重置失败,则会释放连接(TCP为了保证无论在任何环境下都能比较高性能的通信,因此会动态计算这个最大超时时间).

如果收到重发数据,数据重复,tcp会根据收的数据序号自动进行去重

问tcp如何实现可靠性的?

  答:确认应答+超时重传

连接管理

三次握手

在这里插入图片描述
上述过程由内核自动完成,应用程序干预不了.
握手☞的是通信双方进行一次网络交互,相当于客户端与服务器端,通过三次交互,建立了连接(双方各自记录对方的信息)
三次握手的目的就是为了投石问路,验证客户端和服务器端,各自的发送能力与接受能力是否正常!

客户端向服务器发送SYN报文问服务器你准备好了没,服务器返回SYN+ACK报文说我准备好了,你呢?客户端发送ACK告诉服务器我准备好了,到此连接建立成功.

四次挥手

在这里插入图片描述
进行断开连接,断开连接服务器与客户端都有可能先进行发起FIN结束报文.
为什么是四次挥手而不是三次挥手呢?
ack与fin有一定概率合并成为一个的!!但通常情况下不能合并!
ack与fin是不会同时触发的,因为ack是系统内核完成的,而fin而是由应用程序来进行控制的,调用socket的close方法才会触发fin!!!

滑动窗口

发送方一次发多条数据到一定程度停止发送,发送方一次等待多个ack,收到一条ack报文发送一条数据,形似一个滑动的窗口.
在这里插入图片描述

在这里插入图片描述
出现丢包情况:

  1. 数据包到达,ACK报文丢失
    这种情况没啥影响,只要最后几个ack报文收到,就表明前面的ack也都收到了(确认序号的含义表示的是该序号之前的所有数据都已经收到).
  2. 数据包未到达
    在这里插入图片描述

如果是这种情况,应答报文一直显示已经接受到了1001,1001到2000会超时重传,而后面数据的接受是不会受影响的,当1001到2000接受到后,会直接返回已接受数据的最后一个字节的下一个字节的序号.
上述超时重传称为快述重传.

流量控制

本质就是让接收方来限制一下发送方的速度-根据接收端的处理能力,来决定发送端的发送速度.
当ACK报文头部的ack位为1时,报头的窗口大小字段就会生效,返回一个窗口大小来决定发送方发送的速度.
当发送方,发现对方接收缓冲区满了之后,就会暂停发送,但仍然会每隔一段时间触发一个"窗口探测"报文,如果探测一会发现窗口大小不为0,则继续发送.

拥塞控制

TCP引入 慢启动 机制,先发少量的数据,探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传输数据.
衡量了传输路径的处理能力–木桶效应(传输路劲上某一个路由器可用传输速率很小,那么这个路由器的传输能力即为传输路径上的最大传输能力)
通过实验的方式,找到一个合适的发射速率–先开始以一个较小的速率发送,不丢包的情况下提高速率,如果丢包,立即调小速率. 达到一个动态平衡.

    实际发送的窗口大小=将拥塞窗口和接收端主机反馈的窗口大小(流量控制窗口)做比较,取较小的值作为

实际发送的窗口
在这里插入图片描述
此图描述: 拥塞窗口先以一个较小值进行传输,无丢包情况下速率开始以指数形式增长,达到一定阈值后以线性进行增长(避免一下子超过上限很多),当开始出现丢包情况时认为当前窗口已达路径上限,且窗口回到一个较小值,阈值更新为为上限的一半;

延迟应答

延时应答的核心在于让ACK应答报文稍微延时一会儿应答,那么此时应答报文中的接受方缓冲区大小大概率比立即返回大一点(应用程序一直从接收缓冲区读取数据),此时发送方可发送的数据就会多一点.
窗口越大,网络吞吐量就越大,传输效率就越高,在保证网络不拥塞的情况下尽量提高传输效率
数量限制:每隔N个包就应答一次;
时间限制:超过最大延迟时间就应答一次;

捎带应答

接收方的应答报文ack稍等一会接收方的响应报文 二者合并为一个数据报进行发送可提高效率.
捎带应答的效果----四次挥手有可呢三次挥完.

面向字节流

粘包问题
A连续给B发送了多个应用层数据报,这些数据就会堆积在B的接收缓冲区,此时B的应用程序再去读这些数据报就会很难分清楚那个是一个完整的数据报,很容易读半个(在TCP的协议头中,没有如同UDP一样的 “报文长度” 这样的字段,站在应用层的角度,看到的只是一串连续的字节数据,不知道从哪个部分开始到哪个部分,是一个完整的应用层数据包).
解决方法:

  1. 约定分割符.
  2. 约定长度(例如约定数据的前四个字节,用来表示数据报的长度).

异常问题

  1. 进程关闭/进程崩溃
    进程没有了,socket是文件,随之关闭,虽然进程没有了,但是连接还在,可进行正常四次挥手.
  2. 主机关机
    所有用户进程被关闭,触发四次挥手,如果没有挥完,比如服务器端发来fin ,客户端没来及ack就关机了.
    此时对端就会重转fin…重传几次后发现没有ack后尝试重置连接,没有成功后就释放连接.
  3. 断电/断网
    1. 如果对方是发送方
      对方就会收不到ack=>超时重传->重置连接->释放连接
    2. 如果对方是接受端
      对方是无法立即知道,你这边是没来得及发数据还是直接没了
      这使tcp的心眺包 保活机制就体现作用了

接收方定期给发送方发送一个心跳包如果有响应就说明对端还存活,如果没有响应而说明对端已经挂了(心跳包时周期性的并没有那么及时,并且判断也没有那么严格).

JavaEE-图书管理系统通常需要包含以下数据库表: 1. 用户表(user):包括用户ID、用户名、密码、邮箱等字段。 2. 图书表(book):包括图书ID、图书名称、作者、出版社、ISBN号等字段。 3. 借阅记录表(borrow_record):包括借阅记录ID、用户ID、图书ID、借阅时间、归还时间等字段。 4. 管理员表(admin):包括管理员ID、管理员名称、密码等字段。 以下是JavaEE-图书管理系统数据库代码示例: ```sql -- 用户表 CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL, `password` varchar(50) NOT NULL, `email` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 图书表 CREATE TABLE `book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `author` varchar(50) NOT NULL, `publisher` varchar(50) NOT NULL, `isbn` varchar(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 借阅记录表 CREATE TABLE `borrow_record` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `book_id` int(11) NOT NULL, `borrow_time` datetime NOT NULL, `return_time` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `fk_user_id_idx` (`user_id`), KEY `fk_book_id_idx` (`book_id`), CONSTRAINT `fk_book_id` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 管理员表 CREATE TABLE `admin` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL, `password` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` -- 相关问题--: 1. 如何创建数据库表? 2. 如何在JavaEE中连接数据库? 3. 数据库中的什么是外键?
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

手插口袋谁也不爱♡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值