http://www.cnblogs.com/lwzz/archive/2011/07/03/2096963.html

TCP是一种流协议(stream protocol)。这就意味着数据是以字节流的形式传递给接收者的,没有固有的"报文"或"报文边界"的概念。从这方面来说,读取TCP数据就像从串行端口读取数据一样--无法预先得知在一次指定的读调用中会返回多少字节(也就是说能知道总共要读多少,但是不知道具体某一次读多少)。

为了说明这一点,我们假设在主机A和主机B的应用程序之间有一条TCP连接,主机A上的应用程序向主机B发送一条报文。进一步假设主机A有两条报文要发送,并两次调用send来发送,每条报文调用一次。很自然就会想到从主机A向主机B发送的两条报文是作为两个独立实体,在各自的分组中发送的,如图 2-25所示。

 

但 不幸的是,实际的数据传输过程很可能不会遵循这个模型。主机A上的应用程序会调用send,我们假设这条写操作的数据被封装在一个分组中传送给B。实际 上,send通常只是将数据复制到主机A的TCP/IP栈中,就返回了。由TCP来决定(如果有的话)需要立即发送多少数据。做这种决定的过程很复杂,取决于很多因素,比如发送窗口(当时主机B能够接收的数据量),拥塞窗口(对网络拥塞的估计),路径上的最大传输单元(沿着主机A和B之间的网络路径一次可 以传输的最大数据量),以及连接的输出队列中有多少数据。下图只显示了主机A的TCP封装数据时可能使用的诸多方法中的4种。在图2-26中,M11和M12表示M1的第一和第二部分,M21和M22与之类似。如图2-26所示,TCP不一定会将一条报文的全部内 容都放在一个分组(一个包)中传送出去。

 

现在,我们从主机B应用程序的角度来看这种情形。总的来说,主机B应用程序任意一次调用recv时,都不会对TCP发送给它的数据量做任何假设。比如,当主机B应用程序读取第一条报文时,可能会出现下列4种结果。

实际上,可能的结果不止4种,但我们忽略了出错和EOF之类的结果。我们还假设应用程序读取了所有可读的数据。

(1)没有数据可读,应用程序阻塞,或者recv返回一条指示说明没有数据可读。到底会发生什么情况取决于套接字是否标识为阻塞,以及主机B的操作系统为系统调用recv指定了什么样的语义。

(2)应用程序获取了报文M1中的部分而不是全部数据。比如,发送端TCP像图2-26D那样对数据进行分组就会发生这种情况。

(3)应用程序获取了报文M1中所有的数据,除此之外没有任何其他内容。如果像图2-26A那样对数据分组就会发生这种情况。

(4)应用程序获取了报文M1的所有数据,以及报文M2的部分或全部数据。如果像图2-26B或图2-26C那样对数据进行分组就会发生这种情况。

注意,这里还有一个定时问题。如果主机B的应用程序在主机A发送了第二条报文之后一段时间内都没有读取第一条报文,那么这两条报文都会成为可读的。这就和图2-26B所示情况相同了。这些描述说明,通常,在任意指定时刻,可读的数据量都是不确定的。

需要再次说明的是,TCP是一个流协议(stream protocol),尽管数据是以IP分组的形式传输的,但分组中的数据量与send调用中传送给TCP多少数据并没有直接关系。而且,接收程序也没有什么可靠的方法可以判断数据是如何分组的,因为在两次recv调用之间可能会有多个分组到来。即使接收端应用程序的响应非常及时,也可能会发生这种情况。例如,一个分组丢失了,而且后继分组都安全到达,TCP会将后继分组中的数据保存起来,直到重传第一个分组并正确收到为止。此时,所有数据对应用程序都是可用的。

TCP会记录它发送了多少字节,以及确认的字节,但它不会记录这些字节是如何分组的。实际上,有些实现在重传丢失分组的时候传送的数据可能比原来的多一些或少一些。

对TCP应用程序来说,就没有"分组(包)"这种概念。如果应用程序的设计与TCP对数据的分组方式有所关联,就应该考虑重新设计这个应用程序了。

既然任意一次指定的读操作中返回的数据量都是不可预测的,就必须在应用程序中做好应对这种情况的准备,这些情况下边界都是由应用程序级维护的。

最简单的情况就是定长报文。在这种情况下,只需要读取报文中固定数量的字节就可以了。

TCP和流的更多相关文章

  1. 10 TCP限流技术

    TCP限流是因为让接收方充分接受完消息,保证数据安全,不会丢失 一.窗口机制介绍 发送端和接收端都拥有一个窗口,当发送端发送数据时,落进窗口的数据被发送,当接受端接受数据时,落进接收端窗口的数据将会被 ...

  2. TCP的流模式与UDP的报文模式对比

    1       案例背景 在学习TCP-IP协议详解卷一时,读到介绍TCP协议的部分,发现TCP的首部是没有报文总长度字段的,而在UDP中是有的,对这个问题的思考引出了两者之间的区别. 2    案例 ...

  3. java网络编程TCP传输—流操作—拿到源后的写入动作

    在网络编程中的TCP传输里,拿到Socket的源后,应该怎么进行读写操作呢,下面我列举了两种方法,希望大家帮忙补充···· 1.利用byte数组作为一个缓冲区进行读写 客户端上传 //获取socket ...

  4. Nginx负载均衡之TCP/UDP流

    负载均衡是指在多个后端服务器之间有效地分配网络流量. 从NGINX Plus R5[1] 版本开始可以代理和负载均衡传输控制协议(Transmission Control Protocol,TCP)通 ...

  5. java网络编程TCP传输—流操作—服务端反馈与客户端接收

    在读取完流后,服务端会向客户端返回一些数据,告诉客户端,已经写完了. 在这里和”流操作—拿到源后的写入动作“差不多,客户端同样以byte与Buffered两种缓冲读取作为例子,同时,.也是希望大家给补 ...

  6. TCP 流模式与UDP数据报模式(转)

    TCP流模式与UDP数据报模式http://blog.csdn.net/s3olo/article/details/7914717 数据报(datagram)通常是指起始点和目的地都使用无连接网络服务 ...

  7. tcp流式传输和udp数据报传输

    所有的书上都说, tcp是流式传输, 这是什么意思? 假设A给B通过TCP发了200字节, 然后又发了300字节, 此时B调用recv(设置预期接受1000个字节), 那么请问B实际接受到多少字节? ...

  8. TCP的三次握手(建立连接)和四次挥手(关闭连接)

    参照: http://course.ccniit.com/CSTD/Linux/reference/files/018.PDF http://hi.baidu.com/raycomer/item/94 ...

  9. [转]关于AS3 Socket和TCP不得不说的三两事

    磨刀不误砍柴工,让我们从概念入手,逐步深入. 所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过"套接字"向网络 ...

随机推荐

  1. 【Cocos2d-HTML5 开发之一】新建HTML5项目及简单阐述与cocos2d/x引擎关系

    真的是有一段时间没写博了,这段时间呢,发生的事情真的挺多,另外自己呢也闲来做了一些自己的喜欢的东西,主要做的还是基于Mac系统的Cocoa框架的各种编辑器吧.(对了,今年初也出了自己第二本书<i ...

  2. node mkdirSync 创建多级目录

    提供一个实用的一次性同步创建多级目录的方法,收藏一下. function makeDir(dirpath) { if (!fs.existsSync(dirpath)) { var pathtmp; ...

  3. 任务31:课时介绍 & 任务32:Cookie-based认证介绍 &任务33:34课 :AccountController复制过来没有移除[Authorize]标签

    任务31:课时介绍 cookie-based网站这边的认证 jwt基于移动端和前后端分离的项目,jwt有一些独特的优势 jwt在asp.net core中的实现机制,了解实现机制并进行扩展.比如非标准 ...

  4. Go语言中的代码重用 - 继承还是组合?

    故事要从我在一个项目中,想要假装的专业一点而遇到的一个陷阱说起. 代码重用 在这个项目中,我们已经有了类似如下的代码: package main import ( "fmt" ) ...

  5. ASP.NET Core MVC 打造一个简单的图书馆管理系统 (修正版)(七) 学生信息增删

    前言: 本系列文章主要为我之前所学知识的一次微小的实践,以我学校图书馆管理系统为雏形所作. 本系列文章主要参考资料: 微软文档:https://docs.microsoft.com/zh-cn/asp ...

  6. hdoj2571【DP基础】

    题意:中文题/ 思路:DP的思想要理解,就是从上一个最优状态使被传到的状态也是最优状态.因为很久没有打DP,所以连简单地这样的都wa了6次:(QAQ废话不多说). 题目要求是从(x,y)到(x,y+1 ...

  7. python 生成器 generator

    一.生成器定义 通过列表生成表达式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢? ...

  8. 字符串-format格式化

    format函数格式化操作(3.6以上) 基本格式: 变量.format(参数,参数,....) 限定符号:(必须在:后面使用) 对齐相关:参数位置:填充符号对齐符号总长度 1:#>20 < ...

  9. ipset 学习总结

    用途:当机器受到网络攻击时,使用 iptables 封 IP,有时候可能会封禁成千上万个 IP,如果添加成千上万条规则, 在一台注重性能的服务器或者本身性能就很差的设备上就不在适用了.ipset 就是 ...

  10. hdu1301 Jungle Roads 基础最小生成树

    #include<iostream> #include<algorithm> using namespace std; ; int n, m; ]; struct node { ...