一、TCP简单介绍

我们经常听人说TCP是一个面向连接的(connection-oriented)、可靠的(reliable)、字节流式(byte stream)传输协议,  TCP的这三个特性该怎么理解呢?

  • 面向连接:在应用TCP协议进行通信之前双方通常需要通过三次握手来建立TCP连接,连接建立后才能进行正常的数据传输,因此广播和多播不会承载在TCP协议上。(谷歌提交了一个RFC文档,建议在TCP三次握手的过程允许SYN数据包中带数据,即 TFO(TCP Fast Open),目前ubuntu14.04已经支持该TFO功能)。但是同时面向连接的特性给TCP带来了复杂的连接管理以及用于检测连接状态的存活检测机制。

  • 可靠性:由于TCP处于多跳通信的IP层之上,而IP层并不提供可靠的传输,因此在TCP层看来就有四种常见传输错误问题,分别是比特错误(packet bit errors)、包乱序(packet reordering)、包重复(packet duplication)、丢包(packet erasure或称为packet drops),TCP要提供可靠的传输,就需要有额外的机制处理这几种错误。因此个人理解可靠性体现在三个方面,首先TCP通过超时重传和快速重传两个常见手段来保证数据包的正确传输,也就是说接收端在没有收到数据包或者收到错误的数据包的时候会触发发送端的数据包重传(处理比特错误和丢包)。其次TCP接收端会缓存接收到的乱序到达数据,重排序后在向应用层提供有序的数据(处理包乱序)。最后TCP发送端会维持一个发送"窗口"动态的调整发送速率以适用接收端缓存限制和网络拥塞情况,避免了网络拥塞或者接收端缓存满而大量丢包的问题(降低丢包率)。因此可靠性需要TCP协议具有超时与重传管理、窗口管理、流量控制、拥塞控制等功能。另外TFO下TCP有可能向应用层提供重复的数据,也就是不可靠传输,但是只会发生在连接建立阶段,我们后续会进行介绍。

  • 字节流式:应用层发送的数据会在TCP的发送端缓存起来,统一分片(例如一个应用层的数据包分成两个TCP包)或者打包(例如两个或者多个应用层的数据包打包成一个TCP数据包)发送,到接收端的时候接收端也是直接按照字节流将数据传递给应用层。作为对比,同样是传输层的协议,UDP并不会对应用层的数据包进行打包和分片的操作,一般一个应用层的数据包就对应一个UDP包。这个也是伴随TCP窗口管理、拥塞控制等。

在接下来的TCP系列中,我们将会依次介绍TCP协议的连接管理、超时与重传、流量控制、窗口管理、拥塞控制、存活检测等机制。在深入介绍这些内容之前我们先来看一下TCP的封装和协议头的格式(TCP/IP的网络分层等基础网络概念本处不在介绍)

二、TCP的封装和协议头的格式

TCP封装在IP报文中的时候,如下图所示,TCP头紧接着IP头(IPV6有扩展头的时候,则TCP头在扩展头后面),不携带选项(option)的TCP头长为20bytes,携带选项的TCP头最长可到60bytes。

其中不携带选项的TCP头如下图所示(其中阴影部分的四个字段表示了相反方向的数据流信息),其中header length字段由4比特构成,最大为15,单位是32比特(32-bit word),即头长的最大值为15*32 bits = 60bytes,因此上面说携带选项的TCP头长最长为60bytes。

TCP头中的相关字段顺序解释如下:

 TCP源端口(Source Port):16位的源端口其中包含发送方应用程序对应的端口。源端口和源IP地址标示报文发送端的地址。

TCP目的端口(Destination port):16位的目的端口域定义传输的目的。这个端口指明报文接收计算机上的应用程序地址接口。

TCP的源端口、目的端口、以及IP层的源IP地址、目的IP地址四元组唯一的标识了一个TCP连接,一个IP地址和一个端口号的组合叫做一个endpoint或者socket。也即一对endpoint或者一对socket唯一的标识了一个TCP连接。接收端的TCP层就是根据不同的端口号来将数据包传送给应用层的不同程序,这个过程叫做解复用(demultiplex)。相应的发送端会把应用层不同程序的数据映射到不同的端口号,这个过程叫做复用(multiplex)。

TCP序列号(序列码SN,Sequence Number):32位的序列号标识了TCP报文中第一个byte在对应方向的传输中对应的字节序号。当SYN出现,序列码实际上是初始序列码(ISN),而第一个数据字节是ISN+1,单位是byte。比如发送端发送的一个TCP包净荷(不包含TCP头)为12byte,SN为5,则发送端接着发送的下一个数据包的时候,SN应该设置为5+12=17。通过系列号,TCP接收端可以识别出重复接收到的TCP包,从而丢弃重复包,同时对于乱序数据包也可以依靠系列号进行重排序,进而对高层提供有序的数据流。另外SYN标志和FIN标志在逻辑上也占用一个byte,当SYN标志位有效的时候,该字段也称为ISN(initial sequence number),详细请参考后续的TCP连接管理。

TCP应答号(Acknowledgment   Number简称ACK Number或简称为ACK Field):32位的ACK Number标识了报文发送端期望接收的字节序列。如果设置了ACK控制位,这个值表示一个准备接收的包的序列码,注意是准备接收的包,比如当前接收端接收到一个净荷为12byte的数据包,SN为5,则发送端可能会回复一个确认收到的数据包,如果这个数据包之前的数据也都已经收到了,这个数据包中的ACK Number则设置为12+5=17,表示17byte之前的数据都已经收到了。在举一个例子,如果在这个数据包之前有个SN为3,净荷为2byte的数据包丢失,则在接受端接收到这个SN为5的乱序数据包的时候,协议要求接收端必须要回复一个ACK确认包,这个确认包中的Ack Number只能设置为3。

头长(Header Length):4位包括TCP头大小,指示TCP头的长度,即数据从何处开始。最大为15,单位是32比特(32-bit word)。

保留(Reserved):4位值域,这些位必须是0。为了将来定义新的用途所保留,其中RFC3540将Reserved字段中的最后一位定义为Nonce标志。后续拥塞控制部分的讲解我们会简单介绍Nonce标志位。

标志(Code Bits):8位标志位,下面介绍。

窗口大小(Window Size):16位,该值指示了从Ack Number开始还愿意接收多少byte的数据量,也即用来表示当前接收端的接收窗还有多少剩余空间。用于TCP的流量控制。

校验位(Checksum):16位TCP头。发送端基于数据内容计算一个数值,接收端要与发送端数值结果完全一样,才能证明数据的有效性。接收端checksum校验失败的时候会直接丢掉这个数据包。CheckSum是根据伪头+TCP头+TCP数据三部分进行计算的。另外对于大的数据包,checksum并不能可靠的反应比特错误,应用层应该再添加自己的校验方式。

优先指针(紧急,Urgent  Pointer):16位,指向后面是优先数据的字节,在URG标志设置了时才有效。如果URG标志没有被设置,紧急域作为填充。加快处理标示为紧急的数据段。

选项(Option):长度不定,但长度必须以是32bits的整数倍。常见的选项包括MSS、SACK、Timestamp等等,后续的内容会分别介绍相关选项。

标志(Code Bits)中的八位标志位分别介绍如下

CWR(Congestion Window Reduce):拥塞窗口减少标志被发送主机设置,用来表明它接收到了设置ECE标志的TCP包,发送端通过降低发送窗口的大小来降低发送速率

ECE(ECN Echo):ECN响应标志被用来在TCP3次握手时表明一个TCP端是具备ECN功能的,并且表明接收到的TCP包的IP头部的ECN被设置为11。更多信息请参考RFC793。

URG(Urgent):该标志位置位表示紧急(The urgent pointer) 标志有效。该标志位目前已经很少使用参考后面流量控制和窗口管理部分的介绍。

ACK(Acknowledgment):取值1代表Acknowledgment Number字段有效,这是一个确认的TCP包,取值0则不是确认包。后续文章介绍中当ACK标志位有效的时候我们称呼这个包为ACK包,使用大写的ACK称呼。

PSH(Push):该标志置位时,一般是表示发送端缓存中已经没有待发送的数据,接收端不将该数据进行队列处理,而是尽可能快将数据转由应用处理。在处理 telnet 或 rlogin 等交互模式的连接时,该标志总是置位的。

RST(Reset):用于复位相应的TCP连接。通常在发生异常或者错误的时候会触发复位TCP连接。

SYN(Synchronize):同步序列编号(Synchronize Sequence Numbers)有效。该标志仅在三次握手建立TCP连接时有效。它提示TCP连接的服务端检查序列编号,该序列编号为TCP连接初始端(一般是客户端)的初始序列编号。在这里,可以把TCP序列编号看作是一个范围从0到4,294,967,295的32位计数器。通过TCP连接交换的数据中每一个字节都经过序列编号。在TCP报头中的序列编号栏包括了TCP分段中第一个字节的序列编号。类似的后续文章介绍中当这个SYN标志位有效的时候我们称呼这个包为SYN包。

FIN(Finish):带有该标志置位的数据包用来结束一个TCP会话,但对应端口仍处于开放状态,准备接收后续数据。当FIN标志有效的时候我们称呼这个包为FIN包。

另外我们一般称呼链路层的发出去的数据包为帧(frame),称呼网络层发给链路层的数据包为包(packet),称呼传输层发给网络层的数据包为段(segment)。但是正如我们描述所用,段、包、帧也经常统称为数据包或者数据报文。

对应用层来说TCP是一个双向对称的全双工(full-duplex)协议,也就是说应用层可以同时发送数据和接收数据。这就意味着数据流在一个方向上的传输是独立于另一个方向的传输的,每个方向上都有独立的SN。

三、TCP中的数据包窗口和滑窗

在TCP的发送端和接收端都会维持一个窗口,因为一个TCP连接是双向的,因此实际上一个TCP连接一共有四个窗口。此处我们先简单介绍一个发送端的窗口如下。图中的数字表示byte也就是和上面介绍的TCP协议头中的SN是对应的,3号byte以及3号之前的数据表示已经发送并且收到了接收端的ACK确认包的数据;4、5、6三个byte表示当前可以发送的数据包,也有可能已经已经发送了但是还没有收到ACK确认包;7号byte及之后的数据表示为了控制发送速率暂时不能发送的数据。其中4-6这三个byte就称呼为窗口大小(window size)。当TCP连接建立的时候,双方会通过TCP头中的窗口大小字段向对方通告自己接收端的窗口大小,发送端依据接收端通告的窗口大小来设置发送端的发送窗口大小,另外在拥塞控制的时候也是通过调整发送端的发送窗口来调整发送速率的。窗口这个词的来源就是当我们从这一个数据序列中单独看4、5、6这几个byte的时候,我们仿佛是从一个"窗口"中观察的一样。此处先简单有个滑窗的概念后续我们讲到TCP的窗口管理的时候会继续进一步介绍TCP的滑窗。

相关补充:
1、TCPIP最初传输层和IP层是同一个层的,关于网络分层的小故事可以参考http://news.cnblogs.com/n/187131/ , IETF上还专门有一个愚人节系列的RFC,参考https://en.wikipedia.org/wiki/April_Fools%27_Day_Request_for_Comments

2、TCP头中CheckSum的计算可以参考资料

http://www.roman10.net/2011/11/27/how-to-calculate-iptcpudp-checksumpart-1-theory/这个连接里面一共三个系列分别是理论、实现、用例和验证。

http://www.tcpipguide.com/free/t_TCPChecksumCalculationandtheTCPPseudoHeader-2.htm

或者参考TCPIP详解卷一第二版(暂时只有英文版,名字TCP/IP Illustrated Volume 1 Second Edition The Protocols) P475页

3、后面涉及的相关RFC文档可以去IETF官网 http://www.ietf.org/查询 直接搜索RFC号码就行了。整个TCP相关的协议体系,IETF梳理后在2015年以RFC7414发布,想了解或者查询TCP相关RFC协议的可以先看看RFC7414协议,以对整个TCP协议有个概括了解

4、目前linux4.4实现上还不支持Nonce标志,可以参考内核代码中struct tcphdr结构对TCP头的定义。关于Llinux不同版本内核TCP实现相关的更新可以查看linux的changelog,网址https://kernelnewbies.org/LinuxVersions  其中有每个版本的changelog 还有对应的修改代码

5、TCP传输中的包重复,不见得是TCP重传导致的,也可能是因为IP层提供的不可靠传输导致的 http://stackoverflow.com/questions/12871760/packet-loss-and-packet-duplication

6、在网络传输过程中NAT可能会修改checksum甚至系列号seq,后面我们讨论窗口管理等内容的时候为了简化不考虑nat修改seq的场景,即认为发送端发包的seq与接收端接收这个包的时候seq相同。

TCP系列01—概述及协议头格式的更多相关文章

  1. 三十天学不会TCP,UDP/IP网络编程-IP头格式祥述

    我又来了,这篇文章还是来做(da)推(guang)介(gao)我自己的!俗话说事不过三,我觉得我下次得换个说法了,不然估计要被厌恶了,但是我是好心呐,一定要相信我纯洁的眼神.由于这两年接触到了比较多的 ...

  2. IP封包协议头/TCP协议头/TCP3次握手/TCP4次挥手/UDP协议头/ICMP协议头/HTTP协议(请求报文和响应报文)/IP地址/子网掩码(划分子网)/路由概念/MAC封包格式

    IP协议头IP包头格式: 1.版本号:4个bit,用来标识IP版本号.这个4位字段的值设置为二进制的0100表示IPv4,设置为0110表示IPv6.目前使用的IP协议版本号是4. 2.首部长度:4个 ...

  3. TCP系列11—重传—1、TCP重传概述

    在最开始介绍TCP的时候,我们就介绍了TCP的三个特点,分别是面向连接.可靠.字节流式.前面内容我们已经介绍过了TCP的连接管理,接下来的这部分内容将会介绍与TCP可靠性强关联的TCP重传. 很多网络 ...

  4. TCP系列54—拥塞控制—17、AQM及ECN

    一.概述 ECN的相关内容是在RFC3168中定义的,这里我简单描述一下RFC3168涉及的主要内容. 1.AQM和RED 目前TCP中多数的拥塞控制算法都是通过缓慢增加拥塞窗口直到检测到丢包来进行慢 ...

  5. TCP系列08—连接管理—7、TCP 常见选项(option)

    一.TCP选项概述 在前面介绍TCP头的时候,我们说过tcp基本头下面可以带有tcp选项,其中有些选项只能在连接过程中随着SYN包发送,有些可以延后.下表汇总了一些tcp选项 其中我标记为红色的部分是 ...

  6. 以太网帧、TCP与UDP段以及IP数据报格式总结

    传输层及其以下的机制由内核提供,是操作系统的一部分,应⽤层由⽤户进程提供应⽤层数据通过协议栈发到⽹络上时,每层协议都要加上⼀个数据⾸部(header),称为封装.不同的协议层对数据包有不同的称谓,在传 ...

  7. keystone系列二:HTTP协议

    一 为何要学习HTTP协议 http协议就是通信的双方共同遵守的标准,就好比要合伙办事的两家公司签署的合同. openstack中各组件是基于restful api通信的,restful api可以单 ...

  8. TCP连接三次握手协议,释放连接四次挥手,以及使用 awl伪造mac地址进行多线程syn洪泛攻击。

    这个TCP连接就是一次追女生-谈恋爱-分手,追求比分手简单,但是分手比追求复杂.哥,谈了半年的女朋友,在就快要成功了的时候分了,原因是因为有人在后面该老子背后搞SYN洪泛攻击,最后女朋友丢失了.学会T ...

  9. TCP系列02—连接管理—1、三次握手与四次挥手

    一.TCP连接管理概述 正如我们在之前所说TCP是一个面向连接的通信协议,因此在进行数据传输前一般需要先建立连接(TFO除外),因此我们首先来介绍TCP的连接管理. 通常一次完整的TCP数据传输一般包 ...

随机推荐

  1. BugkuWEB矛盾

    题目的意思是GET方式,num不能为数字,但是他的值为1,is_numeric(data)函数是判断data是不是数字返回bool类型 GET方式和POST方式区别 HTTP 定义了与服务器交互的不同 ...

  2. 【8086汇编-Day6】关于loop的实验

    实验内容 因为是要复制代码,所以常规来做是取代码段地址来用,所以把cs值mov给ax,但是这只是临时的,ax之后还有别的用途,那就把指令当作数据来存(把ax值 mov给ds,表示这一段地址用作代码段, ...

  3. uCrop 源码剖析

    GitHub: uCrop, 版本为 2.2.2 主要是探究一下内部对于图片按比例的裁剪以及压缩, 应该会更很长一段时间 疑惑点 这里记下一些源码分析过程中遇到的疑惑点 sample/src/main ...

  4. 设置cell高度的两种方法(label高度的可变引起cell高度可变的情况)

    第一种:(iOS8以后可用) 在Xib或stroyboard中(代码也可以) 利用AutoLayout设置好label的约束(比如可以设置四个边都距离屏幕50等方式,必须四个边都要固定好). 在代码部 ...

  5. TCP/IP漫游

    TCP/IP漫游 TCP/IP是互联网的基础协议栈,它包括大大小小几十个协议.本篇文章主要涉及到就是HTTP.TCP.IP协议.我们经常学的网络模型是七层或者五层,实际上一般认为一共只有四层就可以了. ...

  6. 使用Python访问HDFS

    最近接触到大数据,对于Skpark和Hadoop的料及都停留在第一次听到这个名词时去搜一把看看大概介绍免得跟不上时代的层次. 在实际读了点别人的代码,又自己写了一些之后,虽然谈不上理解加深,至少对于大 ...

  7. http知识点 前端

    前端必须明白的http知识点 对于http的报文格式就不多细说了,做为前端开发,我们需要知道前后端联调时的请求和响应之间请求头和返回头之间的关系和每个字段中的涵意,静态文件资源在加载时我们所观察到可性 ...

  8. 不老的神器--namp,awvs

    要会使用的工具 NESSUS nmap awvs hydra burpsuit 工具的话,都有文档,应该多使用 -h 多看官方文档,就会用了. 1.namp基本用法 -iL <inputfile ...

  9. 怎样安装JMeter

    JMeter有图形界面, 而且支持中文! JMeter官网地址: http://jmeter.apache.org/ 点击左上角的下载: 点击下面的.zip后缀的压缩包: 解压到本地: JMeter目 ...

  10. (C#)代理模式

    1.代理模式 为其他对象提供代理以控制对这个对象的访问. 远程代理:为一个对象在不同的地址空间提供举报代表.这样可以隐藏一个对象在不同地址空间的事实. 虚拟代理:是依据需要创建开销很大的对象.通过它来 ...