计算机网络:传输层(TCP详解)

文章目录

  • 前言
  • 一、面向连接传输TCP
    • 1.段结构
      • TCP往返延时(RTT)和超时
    • 2.可靠数据传输
      • TCP发送方事件
      • TCP重传
      • 产生TCP ACK的建议[RFC 1122. RFC 2581]
      • 快速重传
    • 3.流量控制
    • 4.TCP连接管理
      • 同意建立连接(2次握手)
      • TCP三次握手
      • TCP关闭连接(四次挥手)
    • 5.拥塞控制
      • 机制
      • 拥塞感知
      • 速率控制:速率控制方法
      • 联合控制的方法
      • TCP控制策略
  • 总结


前言

TCP报文段结构、可靠数据传输、TCP连接管理(三次握手、四次挥手)、拥塞控制。


一、面向连接传输TCP

  • 点对点:
    • —个发送方,一个接收方
  • 可靠的、按顺序的字节流:
    • 没有报文边界
  • 管道化(流水线):
    • TCP拥塞控制和流量控制设置窗口大小
  • 发送和接收缓存
    在这里插入图片描述
  • 全双工数据:
    • 在同一连接中数据流双向流动
    • MSS:最大报文段大小
  • 面向连接:
    • 在数据交换之前,通过握手(交换控制报文)初始化发送方、接收方的状态变量
  • 有流量控制:
    • 发送方不会淹没接收方

1.段结构

在这里插入图片描述

  • 序号:
    • 报文段首字节的在字节流的编号(在整个字节中的偏移量)
  • 确认号:
    • 期望从另一方收到的下一个字节的序号
    • 累积确认
  • Q:接收方如何处理乱序的报文段——没有规定

如下:主机A向主机B传输的序号42的字节(字母C),序号42字节到了主机B,主机B收到后回显,告诉主机A:我已经收到,我希望你传来43及以后的字节;对于主机B来说它受到主机A的确认号79,说明78及以前的字节主机A收到了,所以后面它将传输79及以后的字节。即:主机B向主机A回传的Seq = 79,ACK = 43。

在这里插入图片描述

TCP往返延时(RTT)和超时

Q:怎样设置TCP超时?

  • 比RTT要长
  • 但RTT是变化的
  • 太短:太早超时
  • 不必要的重传
  • 太长:对报文段丢失反应太慢,消极

Q:怎样估计RTT?

  • SampleRTT:测量从报文段发出到收到确认的时间
  • 如果有重传,忽略此次测量
  • SampleRTT会变化,因此估计的RTT应该比较平滑
  • 对几个最近的测量值求平均,而不是仅用当前的sampleRTT

在这里插入图片描述

在这里插入图片描述

2.可靠数据传输

  • TCP在IP不可靠服务的基础上建立了rdt
    • 管道化的报文段
      • GBN or SR
    • 累积确认(像GBN)
    • 单个重传定时器(像GBN)
    • 是否可以接受乱序的,没有规范
  • 通过以下事件触发重传
    • 超时(只重发那个最早的未确认段:SR)
    • 重复的确认
      • 例子:收到了ACK50,之后又收到3个ACK50

下面首先考虑简化的TCP发送方:

  • 忽略重复的确认
  • 忽略流量控制和拥塞控制

在这里插入图片描述

TCP发送方事件

  • 从应用层接收数据:用nextseq创建报文段
  • 序号nextseq为报文段首字节的字节流编号
  • 如果还没有运行,启动定时器
    • 定时器与最早未确认的报文段关联
    • 过期间隔:TimeOutInterval
  • 超时:
    • 重传后沿最老的报文段
    • 重新启动定时器
  • 收到确认:
    • 如果是对尚未确认的报文段确认
    • 更新己被确认的报文序号如果当前还有未被确认的报文段,重新启动定时器

TCP重传

在这里插入图片描述

产生TCP ACK的建议[RFC 1122. RFC 2581]

在这里插入图片描述

建议的实施见下面讲解

快速重传

  • 超时周期往往太长:
    • 在重传丢失报文段之前的延时太长
  • 通过重复的ACK来检测报文段丢失
    • 发送方通常连续发送大量报文段
    • 如果报文段丢失,通常会引起多个重复的ACK
  • 如果发送方收到同一数据的3个冗余ACK,重传最小序号的段:
    • 快速重传:在定时器过时之前重发报文段
    • 它假设跟在被确认的数据后面的数据丢失了
      • 第一个ACK是正常的;
      • 收到第二个该段的ACK,表示接收方收到一个该段后的乱序段;
      • 收到第3,4个该段的ack,表示接收方收到该段之后的2个,3个乱序段,可能性非常大段丢失了

根据下图通俗总结:下面五个报文段,先来了40-49的报文段,接收方立马回传ACK50的确认,后面本来要传50-59,但是60-69、70-79、80-89报文段依次来了,但是在这三个报文段来之后,接收方都依然依次回传ACK50。

在这里插入图片描述

TCP快速重传示意图:
在这里插入图片描述

在这里插入图片描述

3.流量控制

在这里插入图片描述

在这里插入图片描述

  • 接收方在其向发送方的TCP段头部的rwnd字段“通告”其空闲buffer大小
    • RcvBuffer大小通过socket选项设置(典型默认大小为4096字节)
    • 很多操作系统自动调整RcvBuffer
  • 发送方限制未确认(“in-flight”)字节的个数 ≤ 接收方发送过来的rwnd值
  • 保证接收方不会被淹没

4.TCP连接管理

在正式交换数据之前,发送方和接收方握手建立通信关系:

  • 同意建立连接(每一方都知道对方愿意建立连接)
  • 同意连接参数

同意建立连接(2次握手)

在这里插入图片描述

Q:在网络中,2次握手建立连接总是可行吗?

  • 变化的延迟(连接请求的段没有丢,但可能超时)
  • 由于丢失造成的重传(e.9.req_conn(×))
  • 报文乱序
  • 相互看不到对方

两次握手的失败场景:

  • 第一次发送连接请求,但是在连接确认回复时超时了,就发出第二次连接请求,结果发出去后,超时的确认终于到了,新发的连接未确认,确认连接的是以前超时的请求连接,导致维护了虚假连接。
  • 在上面的情况时,第一次请求连接建立后会发送数据,服务器接收数据,但是当第一次连接关闭后,新连接这时到达服务器得到确认并发送数据,服务器又收到数据。
  • 注意这里,你在第一次连接成功了,然后客户端做的操作会通过此连接传输数据,但是关闭第一次连接后,新连接终于连上,然后开始发送数据,这时的数据就是以前请求的数据,很难保证第一次连接做了其他数据传输,但第二次连接中也有。(类似于你在半连接成功后,第二次新连接成功前做了些操作,此时第一个连接肯定正常,但是第二个连接虽然未连接上,但是也发数据,当第一个关闭连接后,新连接终于连上,开始发送数据但是发送的时以前第一次连接关闭前传输过的老数据。)

在这里插入图片描述

TCP三次握手

  • 三次握手的关键是要确认对方收到了自己的数据包,这个目标就是通过“确认号(Ack)”字段实现的。计算机会记录下自己发送的数据包序号Seq,待收到对方的数据包后,检测“确认号(Ack)”字段,看Ack = Seq + 1是否成立,如果成立说明对方正确收到了自己的数据包。
  • 在开始握手时,客户端和服务器都会选择初始序号,这个初始序号是随机的,这样是为了避免半连接和接收老数据问题——正因为每次建立连接时Seq是随机的,而当个一个连接建立后,服务器和客户端就开始维护成功的连接的状态了,所以其他连接的Seq不在这个维护状态的范围内(如果运气很差随机值在这个维护范围内,那也没办法,网络不能解决所有问题)。
  • 所谓的维护范围:TCP连接的一方A,由操作系统动态随机选取一个32位长的序列号(InitialSequence Number),假设A的初始序列号为1000,以该序列号为原点,对自己将要发送的每个字节的数据进行编号,1001,1002,1003…,并把自己的初始序列号ISN告诉B,让B有一个思想准备,什么样编号的数据是合法的,什么编号是非法的,比如编号900就是非法的,同时B还可以对A每一个编号的字节数据进行确认。如果A收到B确认编号为2001,则意味着字节编号为1001-2000,共1000个字节已经安全到达。同理B也是类似的操作,假设B的初始序列号ISN为2000,以该序列号为原点,对自己将要发送的每个字节的数据进行编号,2001,2002,200…,并把自己的初始序列号ISN告诉A,以便A可以确认B发送的每一个字节。如果B收到A确认编号为4001,则意味着字节编号为2001-4000,共2000个字节已经安全到达。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

实际中,第三次握手通常跟第一次数据传递弄在一起
为什么要三次握手:

  • 第一次握手 :Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常
  • 第二次握手 :Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:对方发送正常,自己接收正常
  • 第三次握手 :Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常

按照现在的理解2次握手是不行的,说根本点就是客户端(发起建立连接的一方)知道服务器(客户端的初始序列号与服务器达成了一致,相对于客户端来说),服务器其实并不知道客户端是否收到自己同步信号。

TCP关闭连接(四次挥手)

  • 客户端,服务器分别关闭它自己这一侧的连接
    • 发送FIN bit = l 的TCP段
  • 一旦接收到FIN,用ACK回应
    • 接到FIN段,ACK可以和它自己发出的FIN段一起发送
  • 可以处理同时的FIN交换

在这里插入图片描述

  • 第一次挥手:Clien发送一个FIN = 1,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
  • 第二次挥手:Server收到FIN = 1后,发送一个ACK给Client,Server进入CLOSE_WAIT状态,Client进入到FIN_WAIT_2状态。
  • 第三次挥手: Server发送一个FIN = 1,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
  • 第四次挥手:Client收到FIN = 1后,Client进入TIME_WAIT状态(假定 ACK 丢失,TIME_WAIT状态使TCP客户重传最后的确认报文),发送ACK给Server,Server进入CLOSED状态,完成四次握手。

在这里插入图片描述

5.拥塞控制

拥塞:

  • 非正式的定义:"太多的数据需要网络传输,超过了网络的处理能力”
  • 与流量控制不同
  • 拥塞的表现/原因:
    • 链路最大的吞吐量有限,当输入速率无限接近链路带宽时,延迟增大。
      在这里插入图片描述
    • 路由器的缓冲区是有限的,缓冲区溢出,新来分组丢失,发送端重传,传输层的输入又增加了重传的输入
    • 发送超时,重传多个分组拷贝
    • 没必要的重传,链路中包括多个分组拷贝
    • 分组经历比较长的延迟(在路由器的队列中排队)
  • 网络中前10位的问题

2种常见的拥塞控制方法:

  • 端到端拥塞控制:没有来自网络的显式反馈
    • 端系统根据延迟和丢失事件推断是否有拥塞
    • TCP采用的方法
  • 网络辅助的拥塞控制:路由器提供给端系统以反馈信息
    • 单个bit置位,显示有拥塞(SNA,DECbit,TCP/IP ECN,ATM)
    • 显式提供发送端可以采用的速率

机制

  • 端到端的拥塞控制机制
    • 路由器不向主机有关拥塞的反馈信息
      • 路由器的负担较轻
      • 符合网络核心简单的TCP/IP架构原则
    • 端系统根据自身得到的信息,判断是香发生拥塞,从而采取动作
  • 拥塞控制的几个问题
    • 如何检测拥塞
      • 轻微拥塞
      • 拥塞
    • 控制策略
      • 在拥塞发送时如何动作,降低速率
        • 轻微拥塞,如何降低
        • 拥塞时,如何降低
      • 在拥塞缓解时如何动作,增加速率

拥塞感知

发送端如何探测到拥塞?

  • 某个段超时了(丢失事件):拥塞
    • 超时时间到,某个段的确认没有来
    • 原因1:网络拥塞(某个路由器缓冲区没空间了,被丢弃)概率大
    • 原因2:出错被丢弃了(各级错误,没有通过校验,被丢弃)概率小
    • 一旦超时,就认为拥塞了,有一定误判,但是总体控制方向是对的
  • 有关某个段的3次重复ACK:轻微拥塞
    • 段的第1个ack,正常,确认该段,期待紧挨着的第二个段
    • 段的第2个重复ack,意味着紧挨的的第二段的后一段(第三段)收到了,第三段乱序到达
    • 段的第2、3、4个ack重复,意味着第二段后的三个段收到了,他们都是乱序到达,但是就是没有第二段,所以第二段丢失的可能性很大
    • 网络这时还能够进行一定程度的传输,拥塞但情况要比第一种好

速率控制:速率控制方法

如何控制发送端发送的速率

  • 维持一个拥塞窗口的值:CongWin

  • 发送端限制已发送但是未确认的数据量(的上限)∶LastBytesent-LastByteAcked ≤ CongWin

  • 从而粗略地控制发送方的往网络中注入的速率
    在这里插入图片描述

  • Congwin是动态的,是感知到的网络拥塞程度的函数

    • 超时或者3个重复ack,Congwin值下降
      • 超时时: Congwin降为1MSS(最大报文段长度),进入慢启动(SS)阶段然后再倍增到Congwin/2(每个RTT),从而进入拥塞避免(CA)阶段
      • 3个重复ack : Congwin降为congwin/2 ,CA阶段
    • 否则(正常收到Ack,没有发送以上情况): congwin跃跃欲试
      • SS阶段:加倍增加(每个RTT)
      • CA阶段:线性增加(每个RTT)

联合控制的方法

发送端控制发送但是未确认的量同时也不能够超过接收
窗口,满足流量控制要求

  • sendWin=min{CongWin, RecvWin};RecvWin是对方接收的空闲尺寸
  • 同时满足拥塞控制和流量控制要求

TCP控制策略

  • 慢启动
  • AIMD:线性增、乘性减少
  • 超时事件后的保守策略

TCP慢启动:

  • 连接刚建立,Congwin = 1MSS
    • 如:MSS = 1460bytes & RTT = 200 msec
    • 初始速率 = 58.4kbps
  • 可用带宽可能MSS/RTT
    • 应该尽快加速,到达希望的速率
  • 当连接开始时,指数性增加发送速率,直到发生丢失的事件
    • 启动初值很低
    • 但是速度很快
  • 当连接开始时,指数性增加(每个RTT)发送速率直到发生丢失事件
    • 每一个RTT,CongWin加倍
    • 每收到一个ACK时,CongWin加1MSS
    • 慢启动阶段:只要不超时或3个重复ack,一个RTT,CongWin加倍
  • 总结:初始速率很慢,但是加速却是指数性的
    • 指数增加,SS时间很短,长期来看可以忽略

在这里插入图片描述

TCP拥塞控制:AIMD

  • 乘性减:
    • 丢失事件后将congwin降为1,将congwin/2作为阙值,进入慢启动阶段(倍增直到congwin/2)
  • 加性增:
    • 当CongWin>阈值时,一个RTT如没有发生丢失事件,将congwin加1MSS:探测

在这里插入图片描述

  • 当收到3个重复的ACKs:
    • congwin 减半
    • 窗口(缓冲区大小)之后线性增长
  • 当超时事件发生时:
    • Congwin被设置成1MSS,进入SS阶段
    • 之后窗口指数增长
    • 增长到一个阈值(上次发生拥塞的窗口的一半)时,再线性增加

Q:什么时候应该将
指数性增长变成线性?
A:在超时之前,当congwin变成上次发生超时的窗口的一半
实现:

  • 变量:Threshold
  • 出现丢失,Threshold设置成CongWin的1/2

在这里插入图片描述


总结

以上就是TCP的讲解。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript <有道翻译之数据解密‘23年12月06日版‘>--案例(三)

前言: 记得上半年还是去年,有道翻译还是直接返回明文数据;现在也跟着,用接口返回加密数据了; 娱乐一下,破他的密文数据... 成品效果图: js部分: 对于找他的密文数据有点费时,针对密文--->搜他地址和启动器不是特别容易,辗转多时(搜:descrypt/json.parse 结合使用更快),有图…

Linux环境下的MySQL安装

文章目录 前提说明1.卸载内置环境2.检查系统安装包3.卸载这些默认安装包4.获取MySQL官方yum源5.安装MySQLyum源,对比前后yum源6.查看yum源是否生效7.安装MySQL服务8.查看相对应的配置文件9.启动服务10.查看启动服务11.登录方法一12.登录方法二13.登录方法三14.设置开…

uniapp实战 —— 分类导航【详解】

效果预览 组件封装 src\pages\index\components\CategoryPanel.vue <script setup lang"ts"> import type { CategoryItem } from /types/index defineProps<{list: CategoryItem[] }>() </script><template><view class"category&…

Codeforces Round 913 (Div. 3)补题

Rook 题目大意&#xff1a;我们给定一个棋盘(如下图)&#xff0c;棋盘上有一个车&#xff0c;问车可以到的位置&#xff0c;任意顺序输出即可。 思路&#xff1a;输出车的行列中非它本身的点即可。 #include<bits/stdc.h> using namespace std; int main() {int t;scanf…

构建一个语音转文字的WebApi服务

构建一个语音转文字的WebApi服务 简介 由于业务需要&#xff0c;我们需要提供一个语音输入功能&#xff0c;以便更方便用户的使用&#xff0c;所以我们需要提供语音转文本的功能&#xff0c;下面我们将讲解使用Whisper将语音转换文本&#xff0c;并且封装成WebApi提供web服务…

【WebSocket】使用ws搭建一个简单的在线聊天室

前言 什么是WebSockets&#xff1f; WebSockets 是一种先进的技术。它可以在用户的浏览器和服务器之间打开交互式通信会话。使用此 API&#xff0c;你可以向服务器发送消息并接收事件驱动的响应&#xff0c;而无需通过轮询服务器的方式以获得响应。 webscokets 包括webscoket…

AntDesignBlazor示例——创建列表页

本示例是AntDesign Blazor的入门示例&#xff0c;在学习的同时分享出来&#xff0c;以供新手参考。 示例代码仓库&#xff1a;https://gitee.com/known/AntDesignDemo 1. 学习目标 使用Table组件创建列表页面使用DisplayName特性显示中文表头使用模板和Tag组件显示高温数据使…

2023站酷CUBE设计大会,以AIGC赋能创意人

12月6日&#xff0c;2023站酷CUBE设计大会在厦门举行。大会以“AI与热爱”为主题&#xff0c;由美图与站酷联合举办&#xff0c;邀请了多位创意先锋进行分享&#xff0c;旨在构建设计新生态&#xff0c;以AIGC内容生产新范式为创意人持续赋能&#xff0c;共同提升设计价值。 美…

简单自定义vuex的设计思路

vuex集中式存储管理应用所有组件的状态&#xff0c;并以响应的规则保证状态以可预测的方式 发生变化。 步骤&#xff1a; 1.Store类&#xff0c;保存选项&#xff0c;_mutations&#xff0c;_actions&#xff0c;getters 2.响应式状态&#xff1a;new Vue方式设置响应式。 …

电脑开机提示“未正确启动”怎么办?

有时我们在打开电脑时&#xff0c;会出现蓝屏&#xff0c;并提示“电脑未正确启动”&#xff0c;那么&#xff0c;这该怎么办呢&#xff1f;下面我们就来了解一下。 方法一&#xff1a;执行系统还原 我们在上文中提到了Windows无法正确启动的问题可能是由于三方程序或者近期的…

Java利用TCP实现简单的双人聊天

一、创建新项目 首先创建一个新的项目&#xff0c;并命名为聊天。然后创建包&#xff0c;创建两个类&#xff0c;客户端&#xff08;SocketClient&#xff09;和服务器端&#xff08;SocketServer&#xff09; 二、实现代码 客户端代码&#xff1a; package 聊天; import ja…

Spring Boot 3.2项目中使用缓存Cache的正确姿势!!!

你是否曾想过为什么在 Spring Boot 应用中缓存是如此重要&#xff1f;答案在于它通过减少数据检索时间来提高性能。在本文中&#xff0c;我们将深入探讨缓存对微服务模式的影响&#xff0c;并探讨根据操作易用性、速度、可用性和可观测性等因素选择正确缓存的重要性。我们还将探…

[RISCV] 发现一个可以看RISC-V CPU行为的开源项目

最近在浏览某大型程序员交友 网站的时候发现一个好玩的项目,介绍如下: A small program that handles mie, msi, mti and trap interrupts and updates some global variables on interrupts. 重点是他下面还放了一张图: 能看到RISCV CSR的行为太酷啦!!! 下面一起setup一…

Sourcepawn脚本入门(二)命令与事件监听

&#x1f34e;Sourcepawn脚本入门(二)命令与事件监听 &#xff08;控制台&#xff09;命令是常用的插件形式&#xff0c;eg. noclip …等都是常用的命令&#xff0c;在游戏中使用也很容易,souremod可以注册自己的命令。 事件的监听则需要考虑到不同的起源游戏支持的事件不同&am…

中文BERT模型预训练参数总结以及转化为pytorch的方法

1.目前针对中文的bert预训练模型有三家&#xff1a; 谷歌发布的chinese_L-12_H-768_A-12 还有哈工大的chinese-bert-wwm / chinese-bert-wwm-ext 以及HuggingFace上的bert-base-chinese(由清华大学基于谷歌的BERT在中文数据集上训练开发的模型&#xff0c;上传在HuggingFace) …

彻底删除VsCode配置和安装过的插件与缓存

前言 当你准备对 Visual Studio Code&#xff08;VSCode&#xff09;进行重新安装时&#xff0c;可能遇到一个常见问题&#xff1a;重新安装后&#xff0c;新的安装似乎仍然保留了旧的配置信息&#xff0c;这可能会导致一些麻烦。这种情况通常是由于卸载不彻底所致&#xff0c…

【LVS实战】04 LVS+Keepalived实现负载均衡高可用

一、介绍 Keepalived 是一个用于 Linux 平台的高可用性软件。它实现了虚拟路由器冗余协议 (VRRP) 和健康检查功能&#xff0c;可以用于确保在多台服务器之间提供服务的高可用性。Keepalived 可以检测服务器的故障&#xff0c;并在主服务器宕机时&#xff0c;自动将备份服务器提…

外卖系统源码开发:打造高效智能化餐饮解决方案

在当今数字化时代&#xff0c;外卖系统成为了餐饮业中不可或缺的一部分。为了满足日益增长的外卖需求&#xff0c;我们将深入探讨外卖系统源码开发的关键技术和创新应用。 1. 技术栈选择 在开始外卖系统源码的开发之前&#xff0c;我们首先需要选择适用的技术栈。一个典型的…

【langchain实战】开源项目-RasaGPT

1、概述 RasaGpt是一个建立在 Rasa 和 Langchain 之上的没有显示界面的LMM聊天机器人平台。它是一个Rasa和Telegram这种利用像Langchain这样的LMM库进行索引、检索和上下文注入的样板及参考实现。 开源地址&#xff1a; GitHub - paulpierre/RasaGPT: &#x1f4ac; RasaGPT is…

揭秘:软件测试中Web请求的完整流程!

在软件开发的过程中&#xff0c;测试是一个至关重要的环节。而在现代互联网应用中&#xff0c;Web请求是很常见的一个测试需求。本文将介绍Web请求的完整测试流程&#xff0c;帮助读者更好地理解软件测试的关键步骤。 一、测试准备阶段 在进行Web请求测试之前&#xff0c;测试团…