16 | 如何理解TCP的“流”? https://time.geekbang.org/column/article/132443

TCP 是一种流式协议在前面的章节中,我们讲的都是单个客户端 - 服务器的例子,可能会给你造成一种错觉,好像 TCP 是一种应答形式的数据传输过程,比如发送端一次发送 network 和 program 这样的报文,在前面的例子中,我们看到的结果基本是这样的:

发送端:network ----> 接收端回应:Hi, network

发送端:program -----> 接收端回应:Hi, program

这其实是一个假象,之所以会这样,是因为网络条件比较好,而且发送的数据也比较少。

为了让大家理解 TCP 数据是流式的这个特性,我们分别从发送端和接收端来阐述。

我们知道,在发送端,当我们调用 send 函数完成数据“发送”以后,数据并没有被真正从网络上发送出去,只是从应用程序拷贝到了操作系统内核协议栈中,至于什么时候真正被发送,取决于发送窗口、拥塞窗口以及当前发送缓冲区的大小等条件。也就是说,我们不能假设每次 send 调用发送的数据,都会作为一个整体完整地被发送出去。

如果我们考虑实际网络传输过程中的各种影响,假设发送端陆续调用 send 函数先后发送 network 和 program 报文,那么实际的发送很有可能是这个样子的。

第一种情况,一次性将 network 和 program 在一个 TCP 分组中发送出去,像这样:...xxxnetworkprogramxxx...

第二种情况,program 的部分随 network 在一个 TCP 分组中发送出去,像这样:TCP 分组 1:...xxxxxnetworkproTCP 分组 2:gramxxxxxxxxxx...

第三种情况,network 的一部分随 TCP 分组被发送出去,另一部分和 program 一起随另一个 TCP 分组发送出去,像这样。TCP 分组 1:...xxxxxxxxxxxnetTCP 分组 2:workprogramxxx...

实际上类似的组合可以枚举出无数种。不管是哪一种,核心的问题就是,我们不知道 network 和 program 这两个报文是如何进行 TCP 分组传输的。

换言之,我们在发送数据的时候,不应该假设“数据流和 TCP 分组是一种映射关系”。就好像在前面,我们似乎觉得 network 这个报文一定对应一个 TCP 分组,这是完全不正确的。

如果我们再来看客户端,数据流的特征更明显。

我们知道,接收端缓冲区保留了没有被取走的数据,随着应用程序不断从接收端缓冲区读出数据,接收端缓冲区就可以容纳更多新的数据。

如果我们使用 recv 从接收端缓冲区读取数据,发送端缓冲区的数据是以字节流的方式存在的,无论发送端如何构造 TCP 分组,接收端最终受到的字节流总是像下面这样:xxxxxxxxxxxxxxxxxnetworkprogramxxxxxxxxxxxx

关于接收端字节流,有两点需要注意:第一,这里 netwrok 和 program 的顺序肯定是会保持的,也就是说,先调用 send 函数发送的字节,总在后调用 send 函数发送字节的前面,这个是由 TCP 严格保证的;

第二,如果发送过程中有 TCP 分组丢失,但是其后续分组陆续到达,那么 TCP 协议栈会缓存后续分组,直到前面丢失的分组到达,最终,形成可以被应用程序读取的数据流。

如果我们再来看客户端,数据流的特征更明显。我们知道,接收端缓冲区保留了没有被取走的数据,随着应用程序不断从接收端缓冲区读出数据,接收端缓冲区就可以容纳更多新的数据。如果我们使用 recv 从接收端缓冲区读取数据,发送端缓冲区的数据是以字节流的方式存在的,无论发送端如何构造 TCP 分组,接收端最终受到的字节流总是像下面这样:xxxxxxxxxxxxxxxxxnetworkprogramxxxxxxxxxxxx关于接收端字节流,有两点需要注意:第一,这里 netwrok 和 program 的顺序肯定是会保持的,也就是说,先调用 send 函数发送的字节,总在后调用 send 函数发送字节的前面,这个是由 TCP 严格保证的;第二,如果发送过程中有 TCP 分组丢失,但是其后续分组陆续到达,那么 TCP 协议栈会缓存后续分组,直到前面丢失的分组到达,最终,形成可以被应用程序读取的数据流。

两个报文是如何进行 TCP 分组传输的更多相关文章

  1. TCP报文格式和三次握手——三次握手三个tcp包(header+data),此外,TCP 报文段中的数据部分是可选的,在一个连接建立和一个连接终止时,双方交换的报文段仅有 TCP 首部。

    from:https://blog.csdn.net/mary19920410/article/details/58030147 TCP报文是TCP层传输的数据单元,也叫报文段. 1.端口号:用来标识 ...

  2. nginx和php-fpm通信的两种方式 unix socket和TCP

    nginx和fastcgi的通信方式有两种,一种是TCP 一种是unix socket TCP使用的是 127.0.0.1:9000端口,将fastcgi_pass参数修改为127.0.0.1:900 ...

  3. 计算机网络(9)-----TCP可靠传输的实现

    TCP可靠传输的实现 以字节为单位的滑动窗口 滑动窗口的滑动是以字节为单位的,发送方A和接收方B在TCP三次握手的前两次握手时协商好了发送窗口和接受窗口的大小,发送方A根据B发送来的确认连接报文中标明 ...

  4. TCP可靠传输的实现

    TCP可靠传输的实现 1.概述      为方便描述可靠传输原理,假定数据传输只在一个方向上进行,即A发送数据,B给出确认 2.以字节为单位的滑动窗口      TCP的滑动窗口是以字节为单位的.为了 ...

  5. TCP/IP传输层,你懂多少?

    1. 传输层的主要功能是什么?2. 传输层如何区分不同应用程序的数据流?3. 传输层有哪些协议?4. 什么是UDP协议?5. 为什么有了UDP,还需要TCP?6. 什么是TCP协议?7. 怎么理解协议 ...

  6. 网络学习笔记(二):TCP可靠传输原理

      TCP数据段作为IP数据报的数据部分来传输的,IP层提供尽最大努力服务,却不保证数据可靠传输.TCP想要提供可靠传输,需要采取一定的措施来让不可靠的传输信道提供可靠传输服务.比如:出现差错时,让发 ...

  7. TCP可靠传输及流量控制实现原理

    一.为什么TCP是可靠传输? 1. 停止等待协议 通过确认与超时重传机制实现可靠传输 在发送完一个分组后,必须暂时保留已发送的分组的副本. 分组和确认分组都必须进行编号. 超时计时器的重传时间应当比数 ...

  8. 计算机网络概述 传输层 TCP可靠传输的实现

    TCP可靠传输的实现 TCP的可靠性表现在:它向应用层提供的数据是 无差错的.有序的.无丢失的,简单的说就是:TCP最终递交给应用层的数据和发送者发送的数据是一模一样的. TCP采用了流量控制.拥塞控 ...

  9. TCP可靠传输详解

    TCP提供了可靠的传输服务,这是通过下列方式提供的: 分块发送:应用数据被分割成TCP认为最适合发送的数据块.由TCP传递给IP的信息单位称为报文段或段(segment) 定时确认重传:当TCP发出一 ...

随机推荐

  1. 实验2 C语言表达式编程应用及输入输出函数( 后附炫彩小人:) )

    实验任务一 #include <stdio.h> int main (){ int a=5,b=7,c=100,d,e,f; d=a/b*c; e=a*c/b; f=c/b*a; prin ...

  2. Demo分享丨看ModelArts与HiLens是如何让车自己跑起来的

    摘要:基于HiLens Kit已经基本开发完成,可部署到HiLens Kit,模型的选择为基于DarkNet53的YOLOv3模型,权重为基于COCO2014训练的数据集,而车道线的检测是基于Open ...

  3. MongoDb学习(五)--Gridfs--上传下载

    版本 <dependency> <groupId>org.springframework.data</groupId> <artifactId>spri ...

  4. JavaDailyReports10_17

    学习JavaWeb第一天 输出我的第一个HelloWorld! 1 <%@ page language="java" import="java.util.*&quo ...

  5. 零基础学习qt4 第七章的第一个例子

    #include <QtGui> #include "extensionDlg.h" ExtensionDlg::ExtensionDlg(QWidget *paren ...

  6. git分支的创建与分支之间合并的底层原理

    开发一个版本,采用的发布流程: (1).从master的最新代码拉取一个开发分支,在上面进行开发(这里假设开发分支为dev) (2).在开发分支上不断地进行提交版本,期间,master也会有因为其他版 ...

  7. windows10系统修改JDK版本后配置环境变量不生效怎么办

    之前安装了个jdk8版本,今天突然想安装个更新版本的jdk11来用,但在安装好JDK11并配置环境变量后发现修改JDK版本后配置的环境变量不生效的.本文就给大家分享一下windows10系统修改JDK ...

  8. 关于一些视图的基本操作(结合YGGL.sql)

    二.操作题 1.创建视图emp_view2,包含员工编号,姓名,所在部门名称和收入. mysql> create or replace view emp_view2 -> as -> ...

  9. 织梦dedecms自增变量autoindex标签的使用(转)

    织梦dedecms自增变量autoindex标签的使用 例1: {dede:arclist titlelen='120' row='8' typeid='2'}         <li clas ...

  10. spark知识点_datasources

    来自官网DataFrames.DataSets.SQL,即sparkSQL模块. 通过dataframe接口,sparkSQL支持多种数据源的操作.可以把dataframe注册为临时视图,也可以通过关 ...