本文描述了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数据流的划分是应用程序的事,应用程序定义好格式,并自己解析,常见的方案有:
- "color: #ff0000">TCP报文
TCP报文格式
TCP报文最终是由IP层发送出去的,封装报文如下:
TCP报文格式如下:
通常使用一个四元组唯一的表示一个TCP连接(client-ip, client-port, server-ip, server-port),但需要注意以下事实:
- "text-align: center">
TCP首部中定义了6个字段,在一个报文中,通常只会出现一个标志,但也允许多个标志同时出现。
- "color: #ff0000">常见报文
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报文。以下是几种典型情况(详细情景在后文“连接控制”小节表述):
- "color: #ff0000">连接控制
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包
- "color: #ff0000">连接控制
- "color: #ff0000">常见报文
- "text-align: center">
tcp协议详解
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?