网络-TCP详解

####一、TCP服务的特点
#####传输层协议主要有两个:TCP协议和UDP协议。相对于UDP协议,TCP最主要的特点就是面向连接、字节流、和可靠传输。但是与UDP相比,TCP除了面向连接、字节流以外还有一些因为这些特性而带来的区别:
#####1、TCP协议的连接是一对一的,所以基于广播和多播的应用程序不能使用TCP服务,而无连接协议UDP则非常适合广播和多播;
#####2、由于TCP协议面向字节流服务,当发送端应用程序连续执行多次写操作时,TCP模块先将这些数据放入TCP发送缓冲区中,当TCP模块真正发送数据时,发送缓冲区中这些等待的数据可能被封装成一个或多个TCP报文段发出。因此,TCP模块发送出的TCP报文段的个数和应用程序执行的写操作次数之间没有固定的数量关系;而UDP则是发送端应用程序每执行一次写操作,UDP模块就将其封装成UDP数据报并发送。
#####3、TCP通过校验和,序列号,确认应答,重发控制,连接管理以及窗口控制等实现可靠性传输。首先,TCP协议采用发送应答机制,即发送端发送的每个TCP报文段都必须得到接收方的应答,才认为该TCP报文段传输成功;其次TCP协议采用超时重传机制,发送端在发送一个TCP报文段之后启动定时器,如果在定时间内未收到应答,则将重传该报文段;最后还有TCP报文段最终是以IP数据报发送的,而IP数据报到达接收端可能乱序,重复,所以TCP协议还会对接受到的TCP报文段重排、整理、再交付给应用层。


####TCP头部结构:

这里写图片描述
#####16目的和源端口号:告知主机该报文段是来自哪(源端口)以及传给哪个上层协议或应用程序(目的端口);
#####32位序号:一次TCP通信过程中某一个传输方向上的字节流的每个字节的变化;
#####32位确认号:用作对另一方发送来的TCP报文段的响应。确认号的值是收到的TCP报文段的序号值加1;
#####4位头部长度:标识该TCP头部有多少个4字节,4位所表示的最大值为15,所以整个TCP头部最长是60字节;
#####6位标志位:

#####①URG标志:表示紧急指针是否有效;
#####②ACK标志:表示确认号是否有效,携带ACK标志的报文段称为确认报文段;
#####③PSH标志:提示接收端应用程序应该立即从TCP缓冲区读走数据,为接受后续数据腾出空间;
#####④RST标志:表示要求对方重新建立连接,携带RST标志的TCP报文段称为复位报文段;
#####⑤SYN标志:表示请求建立一个连接,携带SYN标志的TCP报文段称为同步报文段;
#####⑥FIN标志:表示本端要关闭连接了,携带FIN标志的报文段称为结束报文段;

#####16位窗口大小:该窗口指的是接收通告窗口,告诉本端的TCP缓冲区还能容纳多少字节的数据,这样就可以控制发送数据的速度,实现流量控制;
#####16位校验和:由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏,该校验不仅包括TCP头部,还包括数据部分;
#####16位紧急指针:是一个正的偏移量,它和序号字段的值相加后表示最后一个紧急数据的下一字节的序号。


####TCP连接的建立和关闭
#####关于TCP的连接,之前利用Wireshark抓取过建立连接过程中的信息,可参考http://blog.csdn.net/sssssuuuuu666/article/details/79441513;可通过下图简单的回顾一下,很明显的可以看出一个连接的建立与断开正常过程至少需要来回发送7个包才能完成
这里写图片描述
#####补充一点:在建立TCP连接同时,也可确定发送数据报的单位,我们可以称其为“最大消息长度”(MSS:Max Segment Size)。TCP在传送大量数据时,是以MSS的大小将数据进行分割发送,进行重发时也同样是。在进行三次握手的时候,两端主机都分别告知对方自己的接口能够适应的MSS的大小,然后在挑选一个较小的值投入使用。
这里写图片描述


#####再介绍下TCP连接关闭的过程(四次挥手):
这里写图片描述
#####断开连接的过程是从报文段4开始的(很明显客户端首先发送了一个带FIN标志的报文段)。对应这个图来说:第一步客户端发送了一个带FIN的报文段,代表客户端要求关闭连接;;第二步服务器端发送报文段5来确认该结束报文;第三步客户端数据全部发送完成,发送一个带有FIN和ACK标志位的报文段,代表服务器端数据发送完成,也准备关闭,进入了最后的确认阶段;第四步客户端对于服务器端的关闭信息给予确认;


####半关闭状态
#####由于TCP连接是全双工的,所以允许两个方向的数据传输被独立关闭,所以在上面的图中可以看出当客户端发出结束报文给服务器端时,服务器并没有立即关闭,而是持续将未发送完的数据发送给客户端,直到服务器端也发送结束报文段才断开连接;这个中间的状态就称为半关闭;


####连接超时
#####对于提供可靠服务的TCP,面对当网络繁忙,或客户端访问一个距离它很远的服务器时,可能会导致服务器对于客户端发送出的同步报文段没有应答,此时客户端就会先进行重连(可能执行多次),如果重连无效,则通知应用程序连接超时。具体模拟场景可以参考《Linux高性能服务器编程》;从大佬们测试的结果可以看出当第一个发送的同步报文没有响应的时候,客户端发送了五个TCP报文段,时间间隔分别为1s、2s、4s、8s、16s,每次重连的超时时间都增加一倍,但是具体执行几次重连操作是由/proc/sys/net/ipv4/tcp_syn_retries 内核变量所定义的。


####TIME_WAIT状态
#####还是上面的插图,当客户端收到服务器的结束报文段之后,并没有立即进入CLOSED状态,而是转移到TIME_WAIT状态。在这个状态,客户端连接要等待一般长为2MSL(Max Segment Life报文段最大生存时间,一般建议值为2min)后才能关闭。
#####至于为什么要存在TIME_WAIT状态的原因有两点:
#####1、可靠的终止TCP连接:假设用于确认服务器结束的报文段丢失,那么服务器将重发结束报文段,所以客户端必须停留在某个状态以处理重复收到的结束报文段;
#####2、保证让迟来的TCP报文段有足够的时间被识别并丢弃:Linux系统中,一个TCP端口不能被同时打开多次(两次及以上)。当一个TCP连接处于TIME_WAIT状态时,我们便无法立即占用该连接占用着的端口来建立一个新连接;假设不存在TIME_WAIT状态,则应用程序能立即建立一个和刚关闭的连接相似的连接,新的化身可能会收到属于原来的连接的、携带应用程序数据的TCP报文段,显然这样是不应该发生的。至于TIME_WAIT状态要保持的时间选择为2MSL,则是因为2MSL时间可以确保网络上两个传输方向上尚未被接收到的、迟到的报文段都已经消失。从而可以确保在2MSL后,建立的新连接是安全的,绝对不会收到属于以前应用的数据。


TCP超时重传

#####TCP作为一个可靠的传输协议,当然也得保证在异常网络状况下,还能够控制数据传输可靠。所以TCP协议必须能够重传超时时间内未收到确认的TCP报文段。为此TCP模块为每个TCP报文段都维护了一个重传定时器,该定时器在TCP报文段第一次被发送时启动;如果超时时间内未接收到接收方的应答,TCP模块将重传TCP报文段并充值定时器,至于重传时间间隔以及执行多少次重传,就是TCP重传的策略;Linux系统中,对于在底层IP和ARP开始接管之前TCP最少执行3次重传,对于指定连接放弃前TCP最多可以执行的重传次数为15


####滑动窗口控制
#####TCP为了控制网络性能下降,引入了窗口的概念;窗口大小就是指无需等待而可以继续发送数据的最大值;也就是说发送端主机在发送了一个段以后不必要一直等待当前报文段的确认应答,而是继续发送;在下图中窗口大小为4个段。
这里写图片描述
#####下图白的部分即为窗口,在这窗口内的数据即便没有收到确认应答也可以发送出去;当发送端收到确认应答的情况下,才将窗口滑动到应答中的序列号的位置。


####拥塞控制
#####TCP模块还有一个重要的任务,就是提高网络利用率,降低丢包率,并保证网络资源对每条数据流的公平性,这就是所谓的拥塞控制。主要包括四个部分:慢启动,拥塞避免,快速重传和快速恢复。
#####拥塞控制的最终受控变量是发送端向网络一次连续写入的数据量,称之为发送窗口。不过发送端最终以TCP报文段来发送数据,所以发送窗口限定了发送端能连续发送的TCP报文段数量。发送端需要合理的选择发送窗口的大小,如果发送窗口太小,会引起明显的网络延迟,反之会导致网络拥塞。具体的拥塞处理方法可参考《Linux高性能服务器编程第三章》



以上内容参考自《Linux高性能服务器编程》《图解TCP/IP》
更生动的解释可以看看《图解TCP/IP》