协议簇:TCP 解析:TCP 数据传输

简介

前面,我们分别介绍了 TCP 基础知识以及连接的建立和关闭,以及最重要的 Sequence Number 的概念. 本篇文章,我们来介绍一下 TCP 如何传输数据.

系列文章

协议簇:TCP 解析:基础
协议簇:TCP 解析:建立连接
协议簇:TCP 解析:连接断开
协议簇:TCP 解析:Sequence Number
协议簇:TCP 解析:数据传输

数据传输

当一个 TCP 连接建立成功之后, TCP 段便可以在这条连接上双向传输. 由于底层网络的不稳定,TCP 段可能在传输过程中出错,TCP 协议会重传这些出错的 TCP 段以确保每个段都成功的发送到了对方. 这个过程依赖于 Sequence Number 机制, TCP双方都需要维护一系列连接状态信息,以确保 Sequence Number 机制正常工作.

发送方使用 SND.NXT 字段记录下一个可用的 SEQ. 发送方将使用 SND.NXT 的值作为下一个发送的 TCP 段的 SEQ; 接收方使用 RCV.NXT 字段记录下一个应该收到的 TCP 段的 SEQ 值。发送方使用 SND.UNA 记录最早的已发送但还没有收到确认的 SEQ 值。 当所有数据包被成功发送并收到接收方的ACK时且当前网络空闲, SND.NXT, SND.UNA, RCV.NXT 三个字段的值应该是相同的.

当发送方构建了一个 TCP段并将它发送出去时, 发送方应该增加 SND.NXT 值。 当接收方接收到一个 TCP段时,接收方应该增加 RCV.NXT 并发送相应的 ACK. 当发送方接收到ACK 时,它应该增加 SND.UNA. 增加的幅度等于相应 TCP 段中所包含数据的长度. 注意,从连接建立成功之后,所有的段都应该包含 ACK 信息.

重传超时时间

TCP 会重传那些已经发送,但是一定时间之后还未收到ACK的段. 但是这个“一定时间”的大小的选择非常重要. 如果选择的太小,容易导致链接上充斥着冗余的数据(已经发送但是由于网络慢还未到达对方,但是发送方却由于重传超时时间已经到达,所以重发该段。 最终接收方会收到两个一摸一样的数据)。 如果太大,又会导致失败的数据包在失败之后等待很长时间才能被重传. 这种i情况下的结果是一样的,那就是 TCP 数据传输效率低下.

由于组成网络的物理链路形形色色,因此,没有一个固定的值能在各种情况下完美工作. 因此,这个超时时间应该是动态变化的.

RFC 中介绍了一种方案. 该方案如下:

发送数据,然后等待对应的 ACK,记录这个过程中所需要的时间。 我们称它为 Round Trip Time(RTT).
接着,使用 RTT 计算 Smoothed Round Trip Time(SRTT),计算方法如下:
SRTT=(ALPHA∗SRTT)+((1−ALPHA)∗RTT)SRTT = ( ALPHA * SRTT) + ((1 - ALPHA) * RTT) SRTT=(ALPHASRTT+((1ALPHA)RTT)
然后,使用更新之后的 SRTT 值计算 RTO(Retransmission timeout)的值,计算方法如下:
RTO=min[UBOUND,max[LBOUND,(BETA∗SRTT)]]RTO = min [ UBOUND, max [ LBOUND, ( BETA * SRTT ) ] ] RTO=min[UBOUND,max[LBOUND,(BETASRTT)]]
其中,
UBOUND 和 LBOUND 分别代表超时时间的上限和下限.
ALPHA 是平滑因子(smoothing factor, 比如, 0.8 - 0.9)
BETA 是延迟方差因子 (delay variance factor, 比如, 1.3 - 2.0)

窗口的控制

每个 TCP 段中都包含 Window 字段来通知对方当前接收方能接收的 SEQ 的范围.

使用一个较大的 Window 值,对方会发送更多的数据给接收方。 但是如果太多数据被发送过来,那么这些数据会被丢弃. 这种情况下,会导致额外的重传工作, 增大物理链路的负担; 使用一个较小的 Window 值,将会抑制发送发的发送速率,会导致传输速率低下。

当发送窗口为 0 的时候,发送方应该周期性的给接收方重传数据. RFC 中建议在这种情况下使用 2 分钟作为重传超时时间. 这种情况下的重传的意义是: 确保当接收方又可以接收数据的时候,这个状态能被通告给发送方。

当接收方的窗口大小为 0 时,接收到对方的TCP段后,必须回复相应的ACK, 这个ACK中包含接收方期待接收的 SEQ 值和窗口为 0 的信息.

窗口大小的控制严重的影响着 TCP 连接的数据传输效率。 RFC 中提出了一些建议:

  1. 较小的窗口值会影响发送效率。 因此,建议接收方延迟更新窗口,直到附加分配的大小达到
    最大可能分配大小的 X % (x 的值为 20 - 40)

  2. 建议发送发尽量避免发送太小的段,而应该等到窗口的大小足够了再发送。 但是如果上层用户调用 了 push 接口, 此时应该直接发送数据而不必顾虑段的大小。

    注意, ACK 段应该总是被立即发送,不应该被推迟。

  3. TCP实现应该总是尝试使用大一些的窗口值

总结

至此, RFC 793 中描述的 TCP 介绍完毕。 这里忽略了接口定义的描述.

相关文章:
协议簇:TCP 解析:基础
协议簇:TCP 解析:建立连接
协议簇:TCP 解析:连接断开
协议簇:TCP 解析:Sequence Number

后续,我们会介绍更加直白的TCP,而不再基于 TCP 的规范。

END!

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

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

相关文章

CodeTank iOS App Technical Support

CodeTank iOS App Technical Support For All Email: z253951598outlook.com TEL: 86-17782749061 App Screen Shoots

CentOS 7 防火墙命令

查看防火墙状态 systemctl status firewalld如果已经开启,状态为 active 如果未开启,状态为 inactive 开启防火墙 systemctl start firewalld关闭防火墙 systemctl stop firewalld查看当前防火墙的配置 firewall-cmd --list-all这里,我…

Go Concurrency Patterns: Context

Go Concurrency Patterns: Context 原文地址:https://blog.golang.org/context Introduction 在 Go 语言实现的服务器上,我们总是使用 goroutine 来处理与客户端建立的连接, 给每个连接分配一个独立的 goroutine. 在请求的 handler 中也通常…

Go Concurrency Patterns: Timing out, moving on

原文地址:https://blog.golang.org/concurrency-timeouts 并发变成有它自己的风格. 一个非常好的例子就是 timeout. 虽然 go 的 channel 没有直接支持 timeout 机制,但是要实现它非常容易. 比如说,我们想从一个 channel ch 中接收数据&#…

Go Concurrency Patterns: Pipelines and cancellation

原文地址: https://blog.golang.org/pipelines 简介 Go 语言提供的并发原语使得可以很方便的构建数据流 pipeline,使用这样的 pipeline 可以高效的利用 I/O 和多 cpu 的优势. 这篇文章我们将展示如何构建并使用 pipeline. 什么是 pipeline ? 在 go 语…

QTcpSocket connectToHost 建立连接速度慢问题

问题场景 在使用 QT 开发一个客户端 App 的时候,我们通过 QTcpSocket 与后台服务器进程通信。 后台程序使用其他语言编写。 问题: 在客户端启用之后尝试建立与后台程序的 TCP 连接的时候,发现连接速度非常慢(肉眼可见的慢&#x…

WinSock I/O 模型 -- Select 模型

简介 Select 模型是 WinSock 中最常见的 I/O 模型,这篇文章我们就来看看如何使用 Select api 来实现一个简单的 TCP 服务器. API 基础 Select 模型依赖 WinSock API Select 来检查当前 Socket 是否可写或者可读。 使用这个 API 的优点是我们不需要使用阻塞的 So…

WinSock I/O 模型 -- WSAEventSelect 模型

简介 WSAEventSelect 模型也是 WinSock 中最常见的异步 I/O 模型。 这篇文章我们就来看看如何使用 WSAEventSelect api 来实现一个简单的 TCP 服务器. API 基础 WSAEventSelect WSAEventSelect 用来把一个 SOCKET 对象和一个 WSAEVENT 对象关联起来。 lNetworkEvents 表示…

WinSock I/O 模型 -- WSAAsyncSelect 模型

简介 WSAAsyncSelect 模型也是 WinSock 中常见的异步 I/O 模型。 使用这个模型,网络应用程序通过接收以 Windows 消息为基础的网络事件通知来处理网络请求。 这篇文章我们就来看看如何使用 WSAAsyncSelect api 来实现一个简单的 TCP 服务器. API 基础 要使用 W…

WinSock I/O 模型 -- OVERLAPPED I/O 模型

简介 OVERLAPPED I/O 模型也是 WinSock 中常见的异步 I/O 模型,相比于我们之前提到的 Select 模型,WSAAsyncSelect 模型 和 WSAEventSelect 模型有更好的性能. 为了方便描述,下文我们将称 Overlapped I/O 模型为 “重叠模型”. 重叠模型的…

WinSock I/O 模型 -- IOCP 模型

前言 IOCP 全称 Input/Ouput Completion Ports,中文中翻译一般为“完成端口”,本文中我们使用 IOCP 简写. IOCP 模型是迄今为止最为复杂的一种 I/O 模型,但是同时通过使用 IOCP 我们往往可以达到最佳的系统性能. 当你的网络应用程序需要管理…

GTank iOS App Technical Support

GTank iOS App Technical Support For All Email: z253951598outlook.com TEL: 86-17782749061 App Screen Shoots ​​

证书体系: CSR 解析

原文同时发布于本人个人博客: https//kutank.com/blog/cert-csr/ 简介 CSR 全称 “证书签名请求”(Certificate Signing Request). 本文我们将来详细的学习 CSR 的知识,重点集中在 CSR 所包含的信息,及其意义。 CSR 的作用: CSR 通常由想要获…

胡思乱想

学了一段时间的OGRE,才知道什么才称得上"建筑师",而我们只不过是"砌墙匠" 他们在算法算法,我们在Coding Coding,怎样才能有所改观呢~~~想当初还不如选数学专业再来学计算机可能好些, 但是既然选择了先学计算机这条路,那就先Coding,边Coding边提高数学能力…

关于数据库备份的问题

首先我们来看数据库帮助上面的sql语句: BACKUP DATABASE Northwind TO DISK c:/Northwind.bakRESTORE FILELISTONLY FROM DISK c:/Northwind.bakRESTORE DATABASE TestDB FROM DISK c:/Northwind.bak WITH MOVE Northwind TO c:/test/testdb.mdf, MOVE N…

关于函数指针调用C++非静态成员

当在类里面定义函数指针,而函数指针会指向类里面的成员的时候,这个时候成员需要定义为静态成员。实例代码如下: //.h#define SCMD_REGISTER 0class CCallFuctionList{public:CCallFuctionList();virtual ~CCallFuctionList(void);typedef…

重构心得

重构入手: 1. 找到牵连最广模块。 2. 找到上述模块中需要重构的相关的子类。 3. 原来代码不删除,保证编译运行。 4. 陆续重构其他模块 再列出我觉得可以借鉴的重构方法。【摘自代码大全】 1.保存初始代码。用你的版本控制系统保存一个初始版本&#x…

跨模块中的分配内存问题

现在有dll模块A,dll模块B以及静态库C, C中有个全局Create()函数负责创建对象M,当第二次调用Create()的时候会增加引用计数,并返回原来创建的对象M。Relase()会减少引用计数。当引用计数为0时,销毁对象M。现在在模块A中创建的初始化对象M,模块…

CListControl的OnMouseMove和OnNcHitTest

实际案例如下: 将CListCtrl做成菜单样式。需要处理当鼠标移到ClistCtrl上的事件。 处理逻辑这样:当鼠标移动到CListCtrl区域时候,将CListCtrl上所有ITem置为非选中状态,然后调用HitTest得到行数再将所选行置为选中状态。当鼠标移…

关于函数指针续

前面有提到过关于函数指针调用C非静态成员&#xff0c;解决了在类内调用函数指针的问题。 class CCallFuctionList { public: CCallFuctionList(); virtual ~CCallFuctionList(void); typedef void (CCallFuctionList::*FUNCPTR)(); typedef std::multimap<unsi…