与UDP不同,TCP提供面向连接的、可靠的、基于字节流的传输层协议,且提供差错纠正。

TCP传输的概念

对与分组丢失和比特差错的处理方法,最直接的方法是重发分组,直到它被正确接收。

这需要一种方法来判断:

  1. 接收方是否已收到分组;

  2. 接收方接收到的分组是否与之前发送方发送的一样,接收方给发送方信号以确定自己已经接收到一个分组,这种方法称为确认(ACK)。

所以传输的顺序大致是这样的:

  1. 发送方发送一个分组a,等待一个ACK;

  2. 接收方接收到分组a,发送对应的ACK给发送方;

  3. 发送方接收到ACK,发送下一个分组b;

  4. 同上步骤2;

  ...

  n. 接收方发送传输结束信号,传输结束,进入断开连接过程。

基于以上的步骤,会产生以下的问题:

  1. 发送方对一个ACK的等待时间应该是多少?

  2. ACK丢失了怎么办?

  3. 分组被接收到,但是数据有错怎么办?

讨论一下:

  问题1. 决定等待多长时间与发送方期待为一个ACK等待多长时间有关,将在第14章详细讨论超时重传知识点,但从直观上看,超时重传的时间大概是:发送分组所用的时间 + 接收方处理它和发送一个ACK的时间 + ACK返回到发送方所用的时间 + 发送方处理ACK所用的时间。

  问题2. 当ACK丢失,发送方不容易把这种情况和原分组丢失的情况做区分,所以它只是简单的再次发送原分组。

  问题3. 使用编码来检测一个大的分组中的差错(有很大的概率)一般都很简单,仅使用比其自身小很多的一些比特即可纠正,更简单的编码一般不能纠正差错,但是能检测它们。

每个分组在被源端发送时都会携带一个序列号,接收方使用这个序列号来判断它是否已经见过这个分组,如果见过则丢弃它。

如果发送方到接收方传递即使一个很小的分组都要用很长时间,那么当发送方注入一个分组到通信路径,然后停下来等待直到它收到ACK。因此这个协议被称为"停止和等待"。假设没有分组在传输中丢失和无可挽回地损害,该协议的吞吐量性能(每单位时间发送在网络中的数据量)与M/R成正比,M是分组大小,R是往返时间(RTT)。如果分组丢失和损害的话,情况更糟:"吞吐质"(每单位时间传输的有用数据量)明显要比吞吐量要低。

为了让网络工作的"更繁忙"从而得到更高的吞吐量,允许多个分组同时进入网络,但这也使得网络传输变得复杂。发送方需要考虑什么时间注入一个分组到网络中、注入多少个、等待ACK时如何维持计时器、保存每个还没确认的分组的副本以防需要重传。接收方需要考虑ACK机制可以区分哪些分组收到或没收到、缓存机制允许维护"次序杂乱"的分组(网络中数据包的到达是无顺序规定的)。还有传输过程中考虑的发送方和接收方和传输路径中间的设备三方的传输速率协调等...

针对以上的问题,引出了下面的"窗口"概念。

假设每个分组由一个序列号开始,定义一个分组窗口作为已被发送方注入但还没完全确认(收到对应的ACK)的分组集合,这个窗口的分组数量称为窗口大小。"窗口"的想法来自:如果你把一个通信对话中发送的所有分组排成长长的一行,但只能通过一个小孔来观察它们,你就只能看到它们的一个子集。

图中窗口大小为3。3号分组已经被发送且确认;7号分组在发送方已经准备好但还没被发送。4-6号分组已经被发送但还未收到确认信息(ACK)。发送方下一步可能收到分组4的ACK,这时候窗口向右滑一个分组:分组4被释放,分组7可以被发送。这便是窗口滑动。

一般来说,这个窗口结构在发送方和接收方都会有。发送方的窗口记录着哪些分组可以被释放、哪些分组正在等待ACK、哪些分组还不能被发送。接收方窗口记录着那些分组已经被接收和确认、哪些分组是下一步期望的(和已经分配多少内存来保存它们)、哪些分组即使被接收也将会因内存限制而被丢弃。

尽管窗口结构便于记录在发送方和接收方之间流动的数据,但是...关于窗口应该有多大?如果接收方盒子网络处理不过来发送方的数据率时会发生什么?

于是便需要对数据传输做流量控制了。流量控制经常以下述两种方式之一来进行操作:

  1. "基于速率"的流量控制,给发送方指定某个速率,同时确保数据永远不能超过这个速率发送(这种类型的流量控制最适合流应用程序,可被用于广播和组播发送);

  2. "基于窗口"的流量控制,使用滑动窗口时最流行的方法,这种方法允许窗口大小不是固定的,而是随时间而变动的。为了使用这种技术进行流量控制,必须有一种方法让接收方可以通知发送方使用多大的窗口,这称为"窗口通告"/"窗口更新",发送方使用该值调整其窗口大小。窗口的更新和ACK是有同一个分组携带的,这就意味着发送方往往会在它的窗口滑动到右边的同时调整它的大小。

基于窗口的流量控制时,在没收到它们中任何一个的ACK之前,发送允许注入W个分组到网络中。如果发送方和接收方足够快,网络中没有丢失一个分组以及有无穷的空间的话,意味着通信速率正比于(SW/R)b/s。W是窗口大小,S是分组大小(按比特算),R是往返时间(RTT)。当来自接收方的窗口通告夹带着发送方的值W时,那么发送方的全部速率就被限制而不能超越接收方。这种方法可以很好的保护接收方,但是网络传输路径中的路由器呢?当网络传输路径中的路由器能力低于发送方速率时,会导致丢包。处理这个现象的流量控制被称为"拥塞控制",关于它将在第16章详细解释。

TCP服务模型和可靠性

TCP提供了面向连接的、可靠的字节流服务。面向连接是指使用TCP的两个应用程序必须在它们可交换数据之前,通过相互联系来建立一个TCP连接。

TCP提供一种字节流抽象概念给应用程序使用,使得传输的消息中没有由TCP自动插入的记录标志或消息边界,每个端点独立选择自己的读写大小。TCP也不会解读字节流里的字节内容,它不知道正在交换的数据字节是什么格式,对这个字节流的解读取决于连接中的每个端点的应用程序。

TCP的可靠性基于:TCP的校验和字段、TCP的偏移量和确认号字段、TCP的超时重传。

TCP必须把一个发送应用程序的字节流转换成一组IP可以携带的分组(过程被称为"组包")。这些组包包含序列号,该序列号在TCP中实际代表了每个分组的第一个字节在整个数据流中的字节偏移。这允许分组在传送中是可变大小的,并允许它们组合,这称为"重新组包"。应用程序数据被打散成TCP认为的最佳大小的块来发送,一般使得每个报文段按照不会被分片的单个IP层数据报的大小来划分。有TCP传给IP的块称为报文段,在第15章会看到TCP如何判定一个报文段的大小。

TCP维护了一个强制的校验和,该校验和涉及它的头部、任何相关应用程序数据和IP头部的所有字段。这是一个端到端的伪头部,用于检测传送中引入的比特差错。如果一个待无效校验和的报文段到达,那么TCP会丢弃它,不为被丢弃的分组发送任何确认。然而,TCP接收端可能会对一个以前的(已经确认)的报文段进行确认,以帮助发送方计算它的拥塞控制(第16章介绍)。

当TCP发送一组报文段时,它通常设置一个重传计时器,等待对方的确认接收。TCP只设置一个计时器,当ACK到达时更新超时。如果有一个确认没有及时接收到,这个报文段就会被重传(第14章介绍)。

当TCP接收到连接的另一端的数据时,它会发送一个确认。这个确认可能不会立即发送,而一般会延迟片刻。TCP使用的ACK是累积的,从某种意义来讲,一个指示字节号N的ACK暗示着所有直到N的字节(但不包含N)已经成功被接收了。这对于ACK丢失来说带来了一定的鲁棒性,如果一个ACK丢失,很有可能后续的ACK就足以确认前面的报文段了。

TCP给应用程序提供一种双工服务。一个完整的TCP连接是双向和对称的,数据可以在两个方向上平等的流动,两个方向互相独立。因此,连接的每个端点必须对每个方向维持数据流的一个序列号。

TCP头部和封装

TCP头部紧跟着IP头部或者IPv6扩展头部,基本长度是20字节,带选项的长度可达60字节,常见选项包括最大段大小、时间戳、窗口缩放和选择性ACK。

单独的TCP内部结构如下图:

源端口和目的端口结合了IP头部的源和目的IP地址,唯一地标识了每个连接。

序列号字段标识了TCP发送端到TCP接收端的数据流的一个字节,该字节代表着包含该序列号的报文段的数据中的第一个字节,TCP给每个字节赋予一个序列号,序列号是32位的无符号数,到达2的32次方减1后再循环回到0,初始序列号是随机指定的。

确认号字段包含的值是该确认号的发送方待接收的下一个序列号,即最后被成功接收的数据字节的序列号加1,该字段只有在ACK位字段被启用才有效。

偏移字段的值为TCP首部(包括选项)长度除以4,最小值为20/4=5,长度可变。

保留字段保留以作扩展。

TCP Flags

  1. CWR - 拥塞窗口减小(发送方降低它的发送速率,在第16章介绍)

  2. ECE - ECN回显(发送方接收到了一个更早的拥塞通告,在第16章介绍)

  3. URG - 紧急(紧急指针字段有效,很少被使用,在第15章介绍)

  4. ACK - 确认(确认号指针字段有效,连接建立后一般都是启用状态,在第15章介绍)

  5. PSH - 推送(接收方应尽快给应用程序传送这个数据,没被可靠地实现或者用到,在第15章介绍)

  6. RST - 重置连接(连接取消,经常是因为错误,在第13章介绍)

  7. SYN - 用于初始化一个连接的同步序列号(在第13章介绍)

  8. FIN - 该报文段的发送方已经结束向对方发送数据(在第13章介绍)

窗口大小字段用以通告一个接收端的窗口大小以达到TCP的流量控制。

校验和字段覆盖了TCP的头部和数据以及头部中的一些字段,由发送方进行计算和保存,然后由接收方验证。

紧急指针字段只有在URG位字段被设置时才有效。这个"指针"是一个必须要加到报文段的序列号字段上的正偏移,以产生紧急数据的最后一个字节的序列号。TCP的紧急机制是一种让发送方给另一端提供特殊标志数据的方法。

参考:

《TCP IP 详解卷1:协议》

RFC官方文档

TCP/IP 笔记 - 传输控制协议的更多相关文章

  1. TCP/IP笔记(八)应用层协议

    TCP/IP的应用层涵盖了OSI参考模型中第5.第6.第7层的所有功能,不仅包含了管理通信连接的会话层功能.转换数据格式的标识层功能,还包括与对端主机交互的应用层功能在内的所有功能. 利用网络的应用程 ...

  2. 网络层、传输层、应用层、端口通信协议编程接口 - http,socket,tcp/ip 网络传输与通讯知识总结

    引: http://coach.iteye.com/blog/2024511 什么是TCP和UDP,以及二者区别是什么? TCP的全称为传输控制协议.这种协议可以提供面向连接的.可靠的.点到点的通信. ...

  3. 运输层3——传输控制协议TCP概述

    目录 1. TCP最主要的特点 2. TCP的连接 3. socket在不同场景中的含义 写在前面:本文章是针对<计算机网络第七版>的学习笔记 运输层1--运输层协议概述 运输层2--用户 ...

  4. TCP/IP笔记(四)IP协议

    前言 IP相当于OSI参考模型的第3层--网络层:主要作用是"实现终端节点之间的通信"又称"点对点通信". IP作为整个TCP/IP中至关重要的协议,主要负责将 ...

  5. TCP/IP笔记(二)TCP/IP简介

    上回,主要介绍了下协议和OSI参考模型,并简单了解下网络构成要素,这回该说说TCP/IP了 互联网与TCP/IP的关系   互联网进行通信时,需要相应的网络协议,TCP/IP原本就是为使用互联网而开发 ...

  6. TCP/IP 笔记 - TCP拥塞控制

    拥塞控制是TCP通信的每一方需要执行的一系列行为,这些行为有特定算法规定,用于防止网络因为大规模的通信负载而瘫痪.其基本方法是当有理由认为网络即将进入拥塞状态(或已由于拥塞而出现路由丢包情况)时减缓T ...

  7. TCP/IP笔记(1)

    TCP/IP 背景和介绍 上世纪 70 年代,随着计算机技术的发展,计算机使用者意识到:要想发挥计算机更大的作用,就要将世界各地的计算机连接起来.但是简单的连接是远远不够的,因为计算机之间无法沟通.因 ...

  8. TCP/IP的排头兵――地址解析协议(ARP) (转载)

    转自:http://blog.csdn.net/wangxg_7520/article/details/2488442 一.引言 古人行军打仗,都要有一个可以引领队伍前进方向的排头兵,在TCP/IP网 ...

  9. TCP/IP笔记——UDP

    OSI模型中最下面的两层用来解决两个硬件设备在物理上的通信问题(如规定怎么将电平信号转换为数字信号),相对应的TCP/IP模型中,这部分代表将会将机器封装为一个MAC地址来实现通讯.网络层是关于,具体 ...

随机推荐

  1. maven打包不包含配置文件[z]

    如果使用maven-jar-plugin和maven-dependency-plugin打包,排除配置文件的方法: 上面的配置是把resources下的配置文件不打进项目的jar包中,主要使用的是&l ...

  2. android 隐藏虚拟按钮栏及标题等权限设置

    华为手机有虚拟按钮,根据以下设置方法可以进行隐藏控制 /** * 隐藏虚拟按键,并且全屏 */ protected void hideBottomUIMenu(Context context){ if ...

  3. Hello SIP Protocol

    SIP Request Line Request-Line = Method SP Request-URI SP SIP-Version CRLFMethod:        1. REGISTER ...

  4. Annotation 标注

    1.画出基本图 当图线中某些特殊地方需要标注时,我们可以使用 annotation. matplotlib 中的 annotation 有两种方法, 一种是用 plt 里面的 annotate,一种是 ...

  5. BootStrap常用组件及响应式开发

    BootStrap常用组件 PS:所有的代码必须写在<class="container/container-fluid">容器当中 常用组件包含内容: 字体图标 下拉菜 ...

  6. Julia 下载 安装 juno 开发环境搭建

    Windows平台 Julia 的官网 (https://julialang.org) 下载链接(https://julialang.org/downloads) 下载完成后,如果想安装在 C 盘,则 ...

  7. 【ElasticSearch】 安装

    Elasticsearch简介 Elasticsearch 是一个开源的分布式 RESTful 搜索和分析引擎,能够解决越来越多不同的应用场景 官网地址:https://www.elastic.co ...

  8. IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类

    一.TCP socket ipv6与ipv4的区别 服务器端源代码如下: #include <stdio.h> #include <stdlib.h> #include < ...

  9. 使用Shell脚本对Linux系统和进程资源进行监控

    ShellLinux脚本 摘要:Shell语言对于接触Linux的人来说都比较熟悉,它是系统的用户界面,提供了用户与内核进行交互操作的一种接口.本文我们以Bash做为实例总结了使用Shell对系统和进 ...

  10. spring boot2 集成Redis

    1. 引入依赖 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spr ...