TCP协议特点
TCP,Transmission Control Protocol,传输控制协议。TCP是TCP/IP体系中非常复杂的一个协议。TCP协议的主要特点有:
(1)TCP是面向连接的运输层协议
应用程序在使用TCP协议发送应用数据之前,必须先建立TCP连接。在传送数据完毕后,必须释放已经建立的TCP连接。这就是说,应用进程之间的通信好像在“打电话”,通话前要先拨号建立连接,通话结束后要挂机释放连接。需要注意的是,TCP连接是一条虚连接而不是一条真正的物理连接。
(2)每条TCP连接只能有两个端口(endpoint),每条TCP连接只能是点对点的,一对一的。
(3)TCP提供可靠交付的服务
通过TCP连接传送的数据,无差错、不丢失、不重复、并且按序到达。
(4)TCP提供全双工通信
TCP允许通信双方的应用进程在任何时候都能发送数据。TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送时,应用程序在把数据传送给TCP的缓存后,就可以做自己的事,而TCP在合适的时候就把数据发送出去。在接收时,TCP把收到的数据放入缓存,在上层的应用进程在合适的时候读取缓存中数据。
(5)面向字节流
TCP中的“流”指的是流入到进程或从进程流出的字节序列。面向字节流的含义是,虽然应用程序和TCP的交互是一次一个数据块,但TCP把应用程序交下来的数据看成仅仅是一连串的无结构的字节流。TCP并不知道所传送的字节流的含义。TCP不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系(例如,发送方应用程序交给发送方的TCP共10个数据块,但接收方的TCP可能只用了4个TCP包就把收到的字节流交付给了上层的应用程序)。但接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样。当然,接收方的应用程序必须有能力识别收到的字节流,把它还原成有意义的应用层数据。
简单来说,“面向字节流”就是TCP层看到上层协议数据,就是以单个字节为单位的连续字节流,TCP把每一个字节都按顺序编号。
需要注意的是,TCP面向字节流的特点,并不是说一个TCP报文只包含一个字节的应用层数据啦。TCP会根据对端给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节。
正是因为TCP是面向字节流的,会对应用层交下来的数据包进行“拆包”和“合包”,从某种程度来说,会破坏应用层数据的语义结构,接收方应用程序就可能理解不了收到的数据包。简单举例来说,应用程序A向B发送了三条语句,分别为“我是谁?”、“我在哪里?”及“我要干什么?”,经过TCP的“拆包”和“合包”优化,在接收方B会收到二个TCP数据包,内容分别为“我是谁?我在”,“哪里?我要干什么?”,那么接收方就无法正确的解析出数据。我们称这种问题为“TCP粘包”。因此当我们的应用程序使用TCP作为传输层协议时,需要处理好“TCP粘包”问题,如在应用层增加消息边界,或者为应用每个消息指定消息长度。需要注意的是,HTTP报文是使用TCP协议来通信的,但并没有“TCP粘包”问题,因为HTTP报文自身就有一定的报文结构,所以接收方能够正确解析出HTTP报文。
TCP/UDP协议通信中的X元组
(1)四元组
源IP地址、目的IP地址、源端口、目的端口
(2)五元组
源IP地址、目的IP地址、协议号、源端口、目的端口
(3)七元组
源IP地址、目的IP地址、协议号、源端口、目的端口、服务类型、接口索引
其中协议号指的是协议类型,一般是协议蔟中的传输层协议,比如TCP是6,UDP是17;也可能是网络层协议,比如ICMP是1;也可能是应用层协议,比如OSPF是89。目的主机收到网络数据包后,根据协议号确定送给哪个模块(TCP/UDP/ICMP…)来处理,送给TCP/UDP模块的报文再根据端口号确定送给哪个应用程序来处理。
TCP协议的报文格式
(1)序号
使用WireShark抓包就是seq=m
,表示本次TCP报文的数据块的第一个字节的编号是m。例如一个TCP的seq是301,而携带的数据共用100个字节。这就表明,本报文段的数据的第一个字节的序号是301,最后一个字节的序号是400,也即接下来的报文的seq将是401。
(2)确认号
使用WireShark抓包就是ack=n
,表示已经收到对端[1~n-1]
范围的字节流,期望对端下次发过来的TCP报文的seq是n。
备注:使用WireShark抓包标记位是大写,注意区分,如SYN|ACK|FIN等。
TCP的可靠传输
TCP发送的报文段是交给IP层传送的,但IP层只能提供尽最大努力服务,也就是说,TCP下面的网络所提供的是不可靠的传输。因此TCP必须采用适当的措施才能使得两个运输层之间的通信变得可靠。TCP为了保证可靠传输,提供了如下三种可选的方案。
(1)停止等待协议
停止等待协议的粒度是分组。每发送完一个分组就停止发送,等待对方的ACK确认,在收到确认后再发送下一个分组。若发送方在超过一段时间仍然没有收到确认,就认为刚才发送的分组在网络上丢失了,因而重传这个分组,这个机制称为超时重传。
需要注意的是,停止等待协议的信道利用率很低,传输的效率低下。
(2)连续ARQ协议
连续ARQ协议的粒度是分组。连续ARQ协议中,发送方会维持一个发送窗口,如发送窗口是5个分组,那么发送方可以将发送窗口中的5个分组连续发送出去,然后等待接收端的ACK确认,若此时收到接收到编号为1的分组确认了,那么发送窗口就向前移动一个分组的位置。
需要注意的是,接收方一般都是采用累积确认的方式,也就是说,接收方不必对收到的分组逐个发送确认,而是可以在收到几个分组后,对按序到达的最后一个分组发送确认。相当于告诉发送方,到这个分组为止的所有分组都已正确收到了。
(3)以字节为单位的滑动窗口协议
以字节为单位的滑动窗口协议的粒度是字节。假设发送方收到了接收方发来的确认报文段,其中窗口是20字节,而确认号是31,这表明接收方期望收到的下一个序列是31,而序号30为止的数据已经收到了。根据这个信息,发送方就构造出了如下的发送窗口:
关于以字节为单位的滑动窗口协议更多细节后续再补充。
TCP的流量控制
一般来说,我们总是希望数据传输得更快一点。但如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失。因此所谓流量控制,就是接收方告诉发送发的发送速率不要太快,要让接收方来得及接收。
TCP的拥塞控制
TCP的流量控制是接收方通过可变窗口来调节发送方的发送速率。而TCP的流量控制,往往是发送方自己来主动控制的。目前,TCP的拥塞控制主要有四种算法:
慢开始,slow-start
拥塞避免,congestion avoidance
快重传,fast retransmit
快恢复,fast recovery