TCP协议详解_动力节点Java学院整理

本文描述了TCP协议,首先简单介绍了TCP完成了一些什么功能;介绍了TCP报文格式,以及典型报文的数据格式;接着从链路控制和数据传输两个方面进行了介绍,在TCP中链路控制和数据传输是通过同一个通道进行的,并没有区分控制通道和数据通道;在网络中传输数据(控制或真实数据),网络可能发生拥堵,因此接下来简单描述了主机端进行拥塞控制所采取的方法,也简单提及了中间路由器/交换机进行拥塞避免所采取的主动措施;最后介绍了在TCP中性能分析的一些基本概念点,在开发网络应用程序的时候,需要对应用的网络需求进行一个估计。

本文不是TCP的入门资料,阅读之前需要对TCP有一些基本认识,如三次握手、四次挥手、滑动窗口等。

TCP概述

通常说到TCP,我们都会很自然的想到其为上层提供了一个面向连接、可靠的、端到端的数据流服务,也通常用电话线路来类比一个TCP连接。但这种类比对刚接触到TCP的人来说极易造成误会,我们需要仔细审视这些概念,你将会发现TCP并不是那么面向连接的、也不是那么可靠的、数据也仍然是通过报文的方式进行传输的。实际上TCP是提供了一种“尽力而为”的数据传输模型;同时,它也提供了防止网络拥塞的主机端拥塞控制,试图去了解整个网络的状况,并采取合适的策略(貌似不是TCP应该干的事?)。

TCP的连接并不是指一条实际的或虚拟的链路存在于数据交换的两端,而是指连接的双方都维护了一些资源(如输入输出缓冲区、多种定时器)以及链路状态的信息,并通过双方的控制报文交互管理状态、向用户提供接口修改这些资源的分配。在“连接控制”小节,我们将会仔细审视资源和状态(包括控制状态的报文),若控制报文丢失,那么连接就会处于一种不一致状态,TCP通过一些手段去试图解决这些问题(如持活定时器、保持定时器等等)。

TCP提供了可靠的数据传输服务,其采取的措施是对控制报文和数据报文进行确认、并在超时之后进行重传;并利用滑动窗口协议解决数据数传乱序、收发双方进行流量控制。具体来说就是,对于发送方,TCP按照其认为最合适的长度发送数据报文,并在发出报文之后,启动一个定时器,等待数据的确认报文,若定时器超时后仍没有收到确认报文,则重传该报文;对于接收方,收到数据后,首先检查报文校验和,错误则直接丢弃该报文,不确认(发送端会注意到这个事实,从而重传);收到重复报文,丢弃,不确认;通过双方维护的滑动窗口,TCP会将乱序报文排好序后才提交给上层应用程序。需要注意的是,流量控制与拥塞控制并不是同一回事,流量控制的目的在于防止发送端发送大量数据,超过接收端的处理能力,从而导致丢包等;拥塞控制则在于防止网络中发生拥堵,中间路由器或交换机丢弃报文的情况。

TCP提供数据流服务,上层应用传给TCP的数据,TCP并不加以区分,仅仅是按照自己的需求组合、拆分数据,然后传送给对端,对端TCP协议栈再将数据以发送的顺序递交给上层应用。TCP的数据传送仍然是以IP报文的方式发送到对端的,每次尽力发送MSS大小的报文,在“数据传输”小节我们会看到诸如Nagle算法、TCP_CORK等对流中报文的控制。

TCP本身并不提供报文边界之类的东西,但提供了紧急数据、PUSH标志(并没有提供对外接口)等方式可以模拟报文。通常,TCP数据流的划分是应用程序的事,应用程序定义好格式,并自己解析,常见的方案有:

  • 先传输固定大小的报文长度字段;
  • 按行进行分割(或其他分隔符);
  • 固定长度记录;
  • 各种编码方案,如xml、json、ASN.1、tlv等。

TCP报文

TCP报文格式

TCP报文最终是由IP层发送出去的,封装报文如下:

TCP报文格式如下:

通常使用一个四元组唯一的表示一个TCP连接(client-ip, client-port, server-ip, server-port),但需要注意以下事实:

  • 监听服务器在server-port窗口接受来自客户端的连接,并fork一个子进程处理连接,此时,该四元组却在服务器对应了两个进程(监听进程只处理SYN报文,而子进程却只能处理数据报文和FIN等);
  • 连接的化身,这在后面会详细描述。

在TCP首部的图中,我们主要关注以下几个字段:序号、首部长度、6个标志位、选项,窗口大小、紧急指针都是以字节单位,这里并不关注。

不含选项的TCP首部为20字节,在首部选项中指明了首部有多少个4字节,由于其占了4位,因此首部最多为60字节。

序号字段用来标识TCP数据流中的数据字节流,在建立连接时会以一个ISN进行初始化,每个SYN、FIN等都会消耗掉一个序号。我们并不用太关心这个字段,只是需要知道序号为32位,在长肥管道(容量较大的网络中)序号可能会出现回绕,TCP需要识别。TCP对该字段也进行了相应的扩充(增加选项)。

TCP选项是以1字节类型、1字节长度(可选)、内容(可选)来表示的,可以只有类型,长度字段包含类型和长度本身。常见选项如下图所示,无操作选项通常用来作为填充以满足选项对齐的要求,tcpdump连接建立的输出中通常会包含这些选项:

TCP首部中定义了6个字段,在一个报文中,通常只会出现一个标志,但也允许多个标志同时出现。

  • URG,紧急指针标志位。
  • ACK,确认序号标志位,关于ACK有几点需要注意:a) ACK是累积的,表示接收方已经正确收到了一直到确认序号减一的所有字节;b) TCP通常并不会对每个数据包进行确认,而是采用了捎带确认和延迟确认的技术,捎带确认是指将ACK报文合并到数据报文中去,而延迟确认是TCP维持了一个200ms的定时器,在定时器过期前,若有多个数据需要确认,则一块进行确认,通常是两个报文确认一次,若200ms到了,仍没有新数据需要确认,则不再等待,直接确认该报文;c) ACK报文本身并不会被确认,当ACK丢失时,需要依靠对端超时机制发现(后文详述)。
  • PSH,该标志由TCP自动设置(曾经允许通过接口进行设置,当前多数实现不提供),多数实现在发送者将清空发送缓冲区时设置该标志,即发送者一次将当前发送缓冲区的数据都发送出去了。
  • RST,连接重置标志位。
  • SYN,同步标志位,用来发起一个新建连接。
  • FIN,发送端已经完成了所有的数据发送,不会再发送新的数据,关闭了其发送端,若对端也发送该标志,则完全关闭连接。

常见报文

TCP中除了通常的数据交换报文(数据报文详见后文“数据传输”小节),还有以下一些特殊的控制报文:SYN报文、ACK报文、FIN报文、RST报文、窗口探测报文、持活报文。这里将常见报文列出来,一是为了强调一个事实,TCP的状态变更大部分是通过报文交互进行的;二是对各种控制报文的使用场景进行简单归纳。

SYN报文,用于发起一个新连接,只包含TCP首部,没有数据。一个典型报文输出如下:

10:23:17.543837 IP 192.168.47.1.55366 > krt.9876: Flags [S], seq 2289863414, win 8192, options [mss 1460,nop,wscale 2,nop,nop,sackOK], length 0

ACK报文,用于对控制报文(不包括RST)和数据报文进行确认,参考上一小节关于ACK的一些注意点。该报文可以与其他报文结合在一起,如SYN、数据报文、FIN报文等。单独的ACK本身不含任何数据,只有首部,典型报文输出如下:

10:23:17.544135 IP 192.168.47.1.55366 > krt.9876: Flags [.], ack 1, win 16425, length 0

FIN报文,用于通知对端已经发送完了所有数据,将发送缓冲区中数据发送完成后,可以关闭连接。详细参考后文“连接控制”,用于有序释放连接或者连接半打开。

RST报文,当向一个出现错误的连接发送一个报文的时候,就收到RST报文。以下是几种典型情况(详细情景在后文“连接控制”小节表述):

  • 对端的相应端口上没有监听程序
  • 异常终止连接,SO_LINGER。使用异常方式终止连接,而不是正常的有序终止连接orderly release,可以迫使连接直接丢失未发送的数据;而接收方收到RST报文后,read返回reset错误,从而终止该连接,同时不会进行ACK。
  • 检测半打开连接,一方已经关闭或异常终止连接而另一方还不知道。造成这种状况的原因在于通信的一方没有正确将相应的状态报文成功发送给对端,如主机突然掉电导致FIN报文没有发出去,此时再写该socket,则会得到RST报文。

窗口探测报文(持久探测报文),TCP并不会对不包含数据的ACK报文进行确认,因此可能出现ACK丢失,从而导致窗口通告失败。TCP使用persist定时器,定期的发送一个字节的窗口探测报文。探测报文总是在5~60s之间,也是采用指数后退算法,但不超过60s,该探测报文会一直持续。实现时,使用500ms的定时器。

持活报文,用于查看连接是否仍然存活的控制报文。报文只带有ACK标志,且序号字段为将要发送的序号减一,这样引起对端进行一个ACK,表示接收到重复序号,对端期望的序号为下一个值。

连接控制

TCP是面向连接的协议,正如前面所描述的,并不存在真实的物理或虚拟的链路,TCP的连接是指在通信的双方分配了资源和维护了状态,并通过控制报文控制连接,通过API协调资源。本小节将详细描述实现中对TCP的连接控制。需要注意的是,连接的拥塞控制在本小节不过多涉及,后面单独小节描述。

4个定时器:重传定时器、2MSL定时器、persist定时器、keepalive定时器

连接双方通过以下一些事件来维持连接的状态, 发送方:发送缓冲区、4个定时器、发送窗口、拥塞状态计数器 接收方:接收缓冲区、4个定时器、接收窗口、拥塞状态计数器

TCP连接更详细的描述 通信双方通过一些内部状态保持了彼此的信息,连接关系始终保持,并通过报文交换来进行连接状态的变更。由于是通过报文进行连接状态的维护,所以报文没有正确发出或被接收到时,连接状态就会变成意料之外了;除确认报文本身不被确认,其他报文都会有确认报文进行确认;报文(包括确认报文)可能超时、需要重传。下面是通信过程中一些重要报文的交互序列。

发送方 网络(中间路由器等组成) 接收方

发送方为Windows,接收方为Linux,操作如下

krt@krt:~$ perl ksock.pl --sleep-before-listen=1
Windows下
C:Userwin-krtDesktop>telnet 192.168.47.120 9876    krt@krt:~$ sudo tcpdump -n -i eth0 tcp port 9876 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 13:59:16.575626 IP 192.168.47.1.65281 > 192.168.47.120.9876: Flags [S], seq 2588085696, win 8192, options [mss 1460,nop,wscale 2,nop,nop,sackOK], length 0 13:59:16.575678 IP 192.168.47.120.9876 > 192.168.47.1.65281: Flags [S.], seq 3751549776, ack 2588085697, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0 13:59:16.577107 IP 192.168.47.1.65281 > 192.168.47.120.9876: Flags [.], ack 1, win 16425, length 0 13:59:19.564526 IP 192.168.47.1.65281 > 192.168.47.120.9876: Flags [P.], seq 1:2, ack 1, win 16425, length 1 13:59:19.564747 IP 192.168.47.120.9876 > 192.168.47.1.65281: Flags [.], ack 2, win 229, length 0 13:59:19.565023 IP 192.168.47.120.9876 > 192.168.47.1.65281: Flags [P.], seq 1:13, ack 2, win 229, length 12 13:59:19.763747 IP 192.168.47.120.9876 > 192.168.47.1.65281: Flags [P.], seq 1:13, ack 2, win 229, length 12 13:59:19.763849 IP 192.168.47.1.65281 > 192.168.47.120.9876: Flags [.], ack 13, win 16422, length 0 13:59:19.764023 IP 192.168.47.1.65281 > 192.168.47.120.9876: Flags [.], ack 13, win 16422, options [nop,nop,sack 1 {1:13}], length 0 13:59:23.688209 IP 192.168.47.1.65281 > 192.168.47.120.9876: Flags [F.], seq 2, ack 13, win 16422, length 0 13:59:23.688372 IP 192.168.47.120.9876 > 192.168.47.1.65281: Flags [F.], seq 13, ack 3, win 229, length 0 13:59:23.689053 IP 192.168.47.1.65281 > 192.168.47.120.9876: Flags [.], ack 14, win 16422, length 0

连接建立

连接建立过程中会经历被称为“三次握手”的报文交互。

连接建立过程主要目的在于协商双方通信的细节,双方的初始序列号、窗口大小、最大报文段MSS大小等。

连接断开

数据传输

数据交换(基本的确认、超时、重传,滑动窗口)

交互数据和批量数据交换

拥塞控制

性能和常用网络工具

tcpdump lsof netstat ss /proc
iputils包 net-tools包 iproute2包

(0)

相关推荐

  • udp协议简介_动力节点Java学院整理

    1.UDP简要介绍 UDP是传输层协议,和TCP协议处于一个分层中,但是与TCP协议不同,UDP协议并不提供超时重传,出错重传等功能,也就是说其是不可靠的协议. 2.UDP协议头 UDP端口号 由于很多软件需要用到UDP协议,所以UDP协议必须通过某个标志用以区分不同的程序所需要的数据包.端口号的功能就在于此,例如某一个UDP程序A在系统中注册了3000端口,那么,以后从外面传进来的目的端口号为3000的UDP包都会交给该程序.端口号理论上可以有2^16这么多.因为它的长度是16个bit UDP

  • HTTP协议入门_动力节点Java学院整理

    HTTP 协议是互联网的基础协议,也是网页开发的必备知识,最新版本 HTTP/2 更是让它成为技术热点. 本文介绍 HTTP 协议的历史演变和设计思路. 一.HTTP/0.9 HTTP 是基于 TCP/IP 协议的应用层协议.它不涉及数据包(packet)传输,主要规定了客户端和服务器之间的通信格式,默认使用80端口. 最早版本是1991年发布的0.9版.该版本极其简单,只有一个命令GET. GET /index.html 上面命令表示,TCP 连接(connection)建立后,客户端向服务器

  • tcp、udp、ip协议分析_动力节点Java学院整理

    互连网早期的时候,主机间的互连使用的是NCP协议.这种协议本身有很多缺陷,如:不能互连不同的主机,不能互连不同的操作系统,没有纠错功能.为了改善这种缺点,大牛弄出了TCP/IP协议.现在几乎所有的操作系统都实现了TCP/IP协议栈. TCP/IP协议栈主要分为四层:应用层.传输层.网络层.数据链路层,每层都有相应的协议,如下图 所谓的协议就是双方进行数据传输的一种格式.整个网络中使用的协议有很多,所幸的是每一种协议都有RFC文档.在这里只对IP.TCP.UDP协议头做一个分析. 首先来看看在网络

  • HTTP协议简介_动力节点Java学院整理

    TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性.Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求.Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的.所以Http连接是一种短连接,是一种无状态的连接.所谓的无状态,是指浏览器每次向服务器发起请求的时候,不是通过一个连接,而是每次都建立一个新的连接.如果是一个连接的话,服务器进程中就能

  • HTTP协议详解_动力节点Java学院整理

    一.概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器. HTTP协议,即超文本传输协议(Hypertext transfer protocol).是一种详细规定了浏览器和万维网(WWW = World Wide Web)服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议. HTTP协议是用于从WWW服务器传输超文本到本地浏览器的传送协议.

  • TCP协议详解_动力节点Java学院整理

    本文描述了TCP协议,首先简单介绍了TCP完成了一些什么功能:介绍了TCP报文格式,以及典型报文的数据格式:接着从链路控制和数据传输两个方面进行了介绍,在TCP中链路控制和数据传输是通过同一个通道进行的,并没有区分控制通道和数据通道:在网络中传输数据(控制或真实数据),网络可能发生拥堵,因此接下来简单描述了主机端进行拥塞控制所采取的方法,也简单提及了中间路由器/交换机进行拥塞避免所采取的主动措施:最后介绍了在TCP中性能分析的一些基本概念点,在开发网络应用程序的时候,需要对应用的网络需求进行一个

  • Java BigDecimal详解_动力节点Java学院整理

    1.引言 借用<Effactive Java>这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的.然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合.但是,商业计算往往要求结果精确,例如银行存款数额,这时候BigDecimal就派上大用场啦. 2.BigDecimal简介 BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组

  • Java System类详解_动力节点Java学院整理

    System类是jdk提供的一个工具类,有final修饰,不可继承,由名字可以看出来,其中的操作多数和系统相关.其功能主要如下: • 标准输入输出,如out.in.err • 外部定义的属性和环境变量的访问,如getenv()/setenv()和getProperties()/setProperties() • 加载文件和类库的方法,如load()和loadLibrary(). • 一个快速拷贝数组的方法:arraycopy() • 一些jvm操作,如gc().runFinalization()

  • Java Runtime类详解_动力节点Java学院整理

    一.概述 Runtime类封装了运行时的环境.每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接.一般不能实例化一个Runtime对象,应用程序也不能创建自己的 Runtime 类实例,但可以通过 getRuntime 方法获取当前Runtime运行时对象的引用.一旦得到了一个当前的Runtime对象的引用,就可以调用Runtime对象的方法去控制Java虚拟机的状态和行为. 当不被信任的代码调用任何Runtime方法时,常常会引起SecurityExc

  • Java Scaner类详解_动力节点Java学院整理

    Java.util.Scanner是Java5.0的新特征,主要功能是简化文本扫描.这个类最实用的地方表现在获取控制台输入,其他的功能都很鸡肋,尽管Java API文档中列举了大量的API方法,但是都不怎么地. 一.扫描控制台输入  这个例子是常常会用到,但是如果没有Scanner,你写写就知道多难受了. 当通过new Scanner(System.in)创建一个Scanner,控制台会一直等待输入,直到敲回车键结束,把所输入的内容传给Scanner,作为扫描对象.如果要获取输入的内容,则只需要

  • web.xml详解_动力节点Java学院整理

    一.            Web.xml详解: (一)  web.xml加载过程(步骤) 首先简单说一下,web.xml的加载过程. 当我们去启动一个WEB项目时,容器包括(JBoss.Tomcat等)首先会读取项目web.xml配置文件里的配置,当这一步骤没有出错并且完成之后,项目才能正常地被启动起来.   启动WEB项目的时候,容器首先会去它的配置文件web.xml读取两个节点: <listener></listener>和<context-param><

  • Apache和Nginx的优缺点详解_动力节点Java学院整理

    Apache和Nginx比较 功能对比 Nginx和Apache一样,都是HTTP服务器软件,在功能实现上都采用模块化结构设计,都支持通用的语言接口,如PHP.Perl.Python等,同时还支持正向和反向代理.虚拟主机.URL重写.压缩传输.SSL加密传输等. 在功能实现上,Apache的所有模块都支持动.静态编译,而Nginx模块都是静态编译的, 对FastCGI的支持,Apache对Fcgi的支持不好,而Nginx对Fcgi的支持非常好: 在处理连接方式上,Nginx支持epoll,而Ap

  • Java8新特性之Base64详解_动力节点Java学院整理

    BASE64 编码是一种常用的字符编码,在很多地方都会用到.但base64不是安全领域下的加密解密算法.能起到安全作用的效果很差,而且很容易破解,他核心作用应该是传输数据的正确性,有些网关或系统只能使用ASCII字符.Base64就是用来将非ASCII字符的数据转换成ASCII字符的一种方法,而且base64特别适合在http,mime协议下快速传输数据. JDK里面实现Base64的API 在JDK1.6之前,JDK核心类一直没有Base64的实现类,有人建议用Sun/Oracle JDK里面

  • ajax详解_动力节点Java学院整理

    在过去几年,JavaScript 已从让人事后才想起的偶然对象变成最重要的 Web 语言.如果要指出一个推动这项技术显著进步的因素,那就是基于 Ajax 的应用程序开发的出现. 开发关于该主题的技术 简言之,Ajax 是一种开发技术,支持网站或应用程序,使用实时数据更新界面,无需页面刷新.该功能创建了一种更为流畅且更具桌面风格的用户体验. Ajax 简史 Ajax 的发展历史类似于其他许多一夜成名的技术.尽管 Ajax 似乎不知从何而来,但实际上,它已经存在很长一段时间了.多年的努力使其遍布 W

随机推荐