TCP概述
TCP(传输控制协议)是一种为了在不可靠的网络中提供可靠的端到端通信的协议。 TCP的特点: (1)面向连接 (2)提供可靠的数据传输服务 (3)流量控制 (4)拥塞控制 (5)全双工通信 (6)面向字节流
TCP报文格式
字段 | 长度 | 说明 |
---|
源端口 | 16bit | 标识哪个应用程序发送。 | 目的端口 | 16bit | 标识哪个应用程序接收。 | 序号 | 32bit | TCP链接中传输的数据流中每个字节都编上一个序号。序号字段的值指的是本报文段所发送的数据的第一个字节的序号。 | 确认号 | 32bit | 用来通知对方的TCP收到了哪些字节。只有ACK标识为1,此字段有效。(例如,A发给B的TCP数据报中序号字段位1,报文长度为40bit,那么B接到数据后会给A回复一个TCP报文,该报文的ack值为41,表示收到40bit的数据,期望下个报文的序号应该从41开始,即A下次发给B的TCP报文中seq的值应该为41。) | 数据偏移 | 4bit | 首部长度,指出TCP报文段的数据起始处距离TCP报文段的起始处有多远,以32比特(4字节)为计算单位。最多有60字节的首部,若无选项字段,正常为20字节。(可选项的长度最长为40字节) | 保留字段 | 6bit | 保留为今后使用,必须填0。 | UPG | 1bit | 紧急指针有效标识。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。 | ACK | 1bit | 确认序号有效标识。只有当ACK=1时确认号字段才有效。当ACK=0时,确认号无效。 | PSH | 1bit | 标识接收方应该尽快将这个报文段交给应用层。接收到PSH = 1的TCP报文段,应尽快的交付接收应用进程,而不再等待整个缓存都填满了后再向上交付。 | RST | 1bit | 重建连接标识。当RST=1时,表明TCP连接中出现严重错误(如由于主机崩溃或其他原因),连接将被终止。 | SYN | 1bit | 同步序号标识,用来发起一个连接。SYN=1表示这是一个连接请求或连接接受请求。 | FIN | 1bit | | 窗口大小 | 16bit | TCP的流量控制,窗口起始于确认序号字段指明的值,这个值是接收端正期望接收的字节数。 | 校验和 | 16bit | 用来检验数据传输中的错误。 | 紧急指针 | 16bit | 只有当URG标志置1时紧急指针才有效。TCP的紧急方式是发送端向另一端发送紧急数据的一种方式。紧急指针指出在本报文段中紧急数据共有多少个字节。 | 可选项 | 可变 | TCP协议最初只规定了一种选项,即最长报文段长度(数据字段加上TCP首部),又称为MSS。MSS告诉对方TCP“我的缓存所能接收的报文段的数据字段的最大长度是MSS个字节”。新的RFC规定有以下几种选型:选项表结束,无操作,最大报文段长度,窗口扩大因子,时间戳。 | 填充项 | 可变 | 用来补位,使整个首部长度是4字节的整数倍。 | 应用层数据 | 可变 | 应用层的数据 |
TCP三次握手
在为应用进程传输数据之前,TCP首先要为这两个应用进程建立TCP连接,创建连接成功后才能继续数据传输,建立连接的过程称为“三次握手”。 第一次握手: 由客户端先发起,这个报文段只有TCP首部,没有封装应用层的数据(因为连接还没有建立,不能传输数据)。报文中的标志位SYN为1,表示客户端请求和服务端建立连接。序号seq是表示将要发送数据的字节起始编号,编号是随机,上面用x表示。
第二次握手: 服务端接收到客户端发起的TCP请求后,做为回应,会发送一个TCP报文给客户端。报文中的标志位SYN为1,表示服务端接受客户端发起的请求;标志位ACK为1,使确认号ack生效;序号seq为y,表示服务端将发送的数据的字节起始编号为y(同第一次握手的seq一样的原理);确认号ack为x+1,表示收到客户端上一个TCP报文,期望客户端下次发送序号seq为x+1的报文。
第三次握手: 客户端收到服务端的响应后,需要再发一个TCP报文给服务端。报文中不用再标记SYN,标志位ACK为1,使确认号ack生效;序号seq为x+1(第二次握手的时候服务端回应的报文中,期望下次发的数据的序号为x+1);确认号ack为y+1,表示收到服务端上一个TCP报文,期望客户端下次发送序号seq为y+1的报文(同第二次握手的报文中的ack一样)。
下面模拟客户端(192.168.1.1:61425)与服务端(192.168.1.2:80)建立TCP连接的三次握手过程,进行抓包分析。 第一次握手报文: 客户端(IP:192.168.1.1,端口:61425)向服务端(IP:192.168.1.2,端口:80)发起请求,SYN为1(请求连接),seq为0。 第二次握手报文: 服务端收到客户端的请求后,服务端(IP:192.168.1.2,端口:80)向客户端(IP:192.168.1.1,端口:61425)回应一个TCP报文,SYN为1(接受连接请求),ACK标志位为1(使能ack确认号),seq为0,ack确认号为1(第一次握手的seq值+1,即0+1,表示收到客户端的TCP报文,期望客户端下一个发送的TCP报文的起始序号为1)。 第三次握手报文: 客户端收到服务端的响应后,再次向服务端(IP:192.168.1.2,端口:80)发送一个TCP报文,TCP报文的标志位ACK为1(使能ack确认号),seq为1(第二次握手中ack的值,服务端所期望的报文起始序号),ack确认号为1(第二次握手的seq值+1,即0+1,表示收到服务端的TCP报文,期望访问端下一个发送的TCP报文的起始序号为1)。 经过三次握手后,TCP连接建立成功,两个应用进程之间可以互相发送数据。 当然,并不是每一次握手都能成功。如果服务端没有监听客户端所要连接的端口,则会建立连接失败,当服务端收到客户端的TCP请求报文,请求连接的端口没有相应的服务监听,则服务端会向客户端回应一个TCP报文,TCP报文中的RST标志位为1,告诉客户端连接无法建立。下面模拟TCP建立失败的过程。 服务端回应客户端TCP报文,RST标志位为1,建立连接失败。
TCP四次挥手
两个应用进程之间的数据传输完毕后,就要关闭它们之间的连接。TCP断开连接的过程需要四步,称为四次挥手。 第一次挥手: 当客户端应用进程关闭时(例如关闭网页),客户端会向服务端发出一个TCP报文,TCP报文中标志位FIN为1,表示告诉服务端:我的数据都传输完毕了,我要关闭连接了。 第二次挥手: 服务端收到客户端的TCP报文后,会通知服务进程,同时回应一个TCP报文,TCP报文中ACK标志位为1,表示收到客户端的TCP报文。到这里,从客户端到服务端的连接就释放了(TCP是双向通信的,从客户端到服务端方向的连接释放了,但是服务端到客户端方向的连接还没释放)。此时TCP连接处于半关闭状态。 第三次挥手: TCP连接处于半关闭状态,所以服务端也要释放到客户端的连接,于是,服务端就发送一个TCP报文,TCP报文中标志位FIN为1,告诉客户端关闭连接。(由于客户端请求关闭后就再无发送数据到服务端,所以服务端发送的TCP报文中ack确认号还是第二次挥手中的ack确认号) 第四次挥手: 客户端收到服务端的TCP报文后,通知客户端的应用进程,同时向服务端发送一个TCP报文。此时连接就全部关闭了。双方的TCP都会释放掉这个连接所占用的全部资源。
TCP数据的可靠性传输
TCP建立连接后,两个应用进程之间就可以互相发送数据,应用层将应用数据交给传输层TCP,TCP在应用数据前面添加上TCP首部,形成TCP报文,然后再交给网络层,TCP报文被封装成IP报文发送到目的主机。 在传输的过程中可能会遇到问题: (1)数据丢失: 因为IP协议是采用非连接的传输方式,它是尽力而为的,尽可能的把数据发到对方,但不能保证对方能够完整的收到自己发送的数据。如果IP报文丢失,那么封装在里面的TCP报文也会丢失。 (2)数据乱序: IP也不能保证数据的顺序到达,先发送的数据可能会后到,导致TCP报文乱序。 (3)数据重复: TCP发出数据后,就会等待对方的确认,如果规定时间内没有收到对方的确认,就会认为对方没有收到数据,然后重新发送一遍数据。如果对方已经收到数据,但是对方发送的确认报文中途丢失了,那么TCP收不到确认,就会重新发送数据,这样对方就收到重复的数据。
为了解决这些问题,为应用层提供可靠的传输服务,TCP采取以下的办法: (1)对发送的数据的字节进行编号: TCP把应用层数据的每一个字节进行编号,起始编号在建立连接的时候会随机生成,并且在第一次握手的报文中告诉对方(上面的第一次握手有讲到)。 (2)对接收到的数据进行确认: 接受到数据后,会给对方回复,确认已经收到数据。例如,A给B发送数据,数据的起始编号为x, 数据长度为y;B接收到数据后,会给A回复确认,确认报文中的确认号(ACK)为x+y,表示收到编号x到y的数据,期望A下次发送数据的起始编号为x+y(参考第二次握手)。TCP确认是累积确认的,后面的确认会包含前面的确认。 (3)设定重传定时器: 如果发送的数据在中途丢失了,发送方就会一直等待接收方的确认报文,可是接收方未接收到数据,不会回复确认报文,那么双方就会一直等待下去。因此发送方在发送数据后,就会启动一个定时器,时间到了还没收到对方的确认,那就认为数据在中途丢失了,会重新发送一遍数据给对方,然后重置定时器。
对于上面传输过程可能遇到的问题,我尝试了模拟这些情况,但是模拟不出来,所以我简单画了示意图: (1)TCP报文丢失,定时重传机制: 还有一些笔记没做完整,后面再补全。
|