我们知道在TCP/IP模型中,有时也叫DoD(Department of Defense)模型,TCP/IP简化OSI的七层模型为四层,由下而上分别为:网络接口层,网际层,传输层和应用层。而今天我学习的就是传输层的TCP协议(传输控制协议)。
本文目录:
1.TCP协议简介
2.TCP报文格式
3.TCP的三次握手建立连接和四次挥手拆除连接
4.TCP中的常见状态
5.TCP中的常见计时器
TCP是TCP/IP协议栈中的传输层的协议,TCP协议又叫传输控制协议(Transport Control Protocal),是面向连接的,可靠的字节流服务。它的可靠性体现在:3次握手建立连接,滑动窗口机制,一定的拥塞避免算法,流量控制,以及一定的超时重传机制。在本文中并不介绍它的可靠性的实现机制。。。
要学习TCP协议,首先要了解TCP报文的报文格式,下面是TCP的报文格式及分析。。。
1).16位的源端口号和目的端口号,我们知道端口号就是标识特定主机上的唯一进程的,而IP地址是用来标识网络中的不同主机的,这两个源和目的端口号和IP首部中的源和目的IP地址则标识互联网上的唯一进程,所以套接字的定义说白了就是IP地址和端口号共同组成。
2).32位的序号,是用来标识从TCP发送端向TCP接收端发送的数据字节流的,是一个32位的无符号数。它表示在这个报文段中的的第一个数据字节在数据流中的序号。如果将字节流看作在两个应用程序间的单向流动,则TCP用序列号对每个字节进行计数。用来保证到达数据顺序的编号。
3).32位的确认序号,上一个字段的序号是对数据的编号,所以确认序号是下一个期望接收的TCP分段号,相当于是对对方所发送的并且已经被本方所正确接受的分段的确认。确认序号应当是上次已成功收到数据字节序号加1。不过,只有当标志位中的ACK标志为1时该确认序列号的字段才有效。所以顺序号和确认号共同作用于TCP服务中的确认,差错控制,是用于确保TCP的安全性和可靠性的。
4).4位的报头长度,以32位字长为单位,需要这个值是因为任选字段的长度是可变的。这个字段占4bit(最多能表示15(四位全为1)个32bit的的字,即4*15=60个字节的首部长度),因此TCP最多有60字节的首部。不存在任选字段正常的报头长度是20字节。其实相当于给出数据在数据段中的开始位置。
5).保留位,占6比特,为将来的应用而保留,目前置为'0'。
6).编码位,占有6个比特位,他们中可以有多个为置为1,依次为:URG,ACK,PSH,RST,SYN,FIN。
URG:该位为1说明表示TCP包的紧急指针域有效,用来保证TCP连接不被中断,并且督促中间层设备要尽快处理这些数据。
ACK:该位为1时说明确认字段是有效,反之为0。
PSH:请求急迫操作,这个标志位表示Push操作。所谓Push操作就是指在数据包到达接收端以后,立即传送给应用程序,而不是在缓冲区中排队。
看到这里有的读者就会产生疑问了URG和PSH都是紧急时使用,那仫这两者有什仫区别和联系呢?
答:在一般的数据中都会存在PSH,而URG只有在紧急情况下才会触发TCP报文中的紧急指针字段,那仫什仫样的情况才是紧急情况呢?紧急方式是向对方发送紧急数据的一种方式,表示数据需要优先处理。它是一个正的偏移,与TCP首部中序号字段的值相加表示紧急数据后面的字节,紧急指针是数据最后一个字节,TCP首部中只有紧急指针指出紧急数据的位置,它所指的字节为紧急数据,但没有办法指定紧急数据的长度。
RST:连接复位,复位因主机奔溃或其他原因而出现的错误连接,也可以用于拒绝非法的分段或拒绝连接请求
SYN:是一个同步序号,通常与ACK合用用来建立连接。例如SYN=1,ACK=0表示连接请求;SYN=1,ACK=1则表示同意建立连接。
FIN:既然有建立连接那仫必然有拆除连接,这个字段表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送FIN标志位的TCP数据包后,连接将被断开。这个标志的数据包也经常被用于进行端口扫描。
7).16位的窗口大小,TCP的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收的字节。这是一个16 bit字段,因而窗口大小最大为65535字节。
8).16位的校验和,用于对分段首部和数据进行校验。通过将所有16位的数据以补码的形式相加,然后再对相加和取补,正常情况下为0.
9).16位的紧急指针, 只有当URG标志置1时紧急指针才有效。紧急指针是一个正的偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。TCP的紧急方式是发送端向另一端发送紧急数据的一种方式。
选项和数据在这里不详细解释。。。
三.TCP的三次握手建立连接与四次挥手拆除连接
1.三次握手建立连接
TCP使用三次握手来建立连接,该连接可以由任意一方发起,也可以由双方同时发起,那仫为什仫需要3次握手?每次握手都做了什仫呢?下面就来一一解决上面的问题。。。先来看三次握手建立连接的过程
第一次握手:发送方首先发起TCP建立连接的请求,SYN=1,ACK=0,seq=x,此时发送方进入并进入SYN_SEND状态,等待服务器确认;
第二次握手:接收端收到SYN,同意建立连接,SYN=1,ACK=1,ack=x+1(对发送方回应的确认字段),seq=y,此时接收端进入此时服务器进入SYN_RECV状态;
第三次握手:发送方收到接收端发来的同意建立连接的分段,如果此时确认真的要建立连接,则想接收端发送确认字段,ACK=1,ack=y+1(对接收端做出的回应)。发送方和接收方进入ESTABLISHED状态,完成三次握手。
下图是一个三次握手建立连接的简单示意图:
了解了三次握手的实现原理,下面我们就来讨论一下为什仫TCP需要3次握手建立连接,而不是2次,4次以及n次?
答:假设一下如果是两次握手建立连接会发生什仫情况呢?两次握手说明只有请求和应答,假如发送方给接收方发送了一个建立连接的请求,接收方收到了并给发送方做出了ACK应答,然而此时网络不太好,这个应答在回复的路上出了发生了阻塞,延迟了。发送方长时间未收到接收方的回应,认为建立连接失败(但是此时接收方认为连接已经建立好了),于是发送方重新给接收方发送建立连接的请求,此时延迟的ACK应答到达了发送方就会造成网络更加阻塞。而三次握手正好避免了这个问题,如果接收方的ACK应答发生延迟现象,因为是3次握手所以发送方认为自己还没有给接收方发送确认建立连接的字段,所以并不认为连接建立失败,不会重发建立连接的请求;至于为什仫不是4次,以及n次,既然3次握手已经可以成功了建立连接又为什仫要多此一举呢???(解释的比较粗糙啦!!!)
2.四次挥手拆除连接
在上面提到了TCP的三次握手建立连接,那仫如何拆除连接呢?就是四次挥手拆除连接。因为TCP的连接时全双工的,所以拆除连接需要拆除两个单向的连接,那仫具体的拆除连接每步都做了什仫呢?详细的介绍见下文。。。
第一次挥手:当发送方的主机已经发送完毕的时候,在等待接收端的确认的同时,可以向另一端发送拆除连接的请求。FIN=1,ACK=1,seq=u;
第二次挥手:当接收端已经正确接受发送端的所有数据包,会发送一个ACK应答,同时通知本地相应的应用程序;如果此时对方要求关闭连接,此时再发送一个ACK的分段进行确认。ACK=1,FIN=0,ack=u+1;
第三次挥手:因为TCP的连接时全双工的所以也需要拆除接收方到发送方的连接,此时接收端发送一个FIN的报文段。FIN=1,ACK=1,seq=w;
第四次挥手:发送方收到这个FIN字段,发回一个ACK应答。ACK=1,FIN=0,seq=u+1,ack=w+1;
一个TCP连接是全双工的(即数据在两个方向上能同时传递),因此每个方向必须单独地进行关闭,所以正常的终止一个连接需要四次握手。收到一个FIN只意味着在这一方向上没有数据流动。一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方(即发送第一个FIN)将执行主动关闭,而另一方(收到这个FIN)执行被动关闭。通常一方完成主动关闭而另一方完成被动关闭。
首先需要了解TCP中有哪些状态每个状态都有什仫意义?下面就来详细的介绍。。。
1).CLOSED:表示初始状态.
2).LISTEN:表示服务器端的某个SOCKET处于监听状态,可以接受连接。
3).SYN_RCVD:这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手 过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。
4).SYN_SENT:这个状态与SYN_RCVD有关,当客户端发送SYN报文,因此也随即会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。
5).ESTABLISHED:表示连接已经建立了。
6).FIN_WAIT_1:其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态有什仫区别呢?FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当接受到对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。
7).FIN_WAIT_2:实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求关闭连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。
8).TIME_WAIT:表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标 志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。
9).CLOSING:这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一 个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。
10).CLOSE_WAIT:这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话, 那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。
11).LAST_ACK: 它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。
在上图中可以发现存在2*MSL超时重传机制,为什仫在拆除连接后要等待该2*MSL的时间?
答:我们知道在发送方和接收方拆除连接后会等该一定的时间,这是为了防止刚被释放的端口立即被释放,在RFC中该超时时间一般为120s。如果在两倍最大分组生存期内FIN的应答没有到达的话,FIN的发送方就会直接释放连接;而接收方也会注意到,对方已经不再监听了,于是不再发送,连接拆除。。。。
五.TCP协议中的常见计时器
TCP协议通常包含四种计时器:重传计时器,持续计时器,保活计时器和时间等待计时器。
1.重传计时器(Retransmission Timer),该计时器用于整个连接期间,用于处理RTO(重传超时)。当一个报文从发送队列发出去后,就启动该计时器,若在RTO之内收到了该报文的ACK,则停止该重传计时器;若t>=RTO都还没有收到报文的ACK,则重传该报文,并清空该重传计时器。
注意:若ACK报文捎带其它信息,则不会为该报文设置重传计时器。
2.持续计时器(Persistent Timer),用于处理零窗体值的通过,防止"死锁"现象。
假若接收端的TCP要命令发送端的TCP停止发送报文段时,就向发送方发送TCP发送一个报文段,该报文的窗体大小字段为0,这就是零窗体值。发送端的TCP收到该零值窗体值报文后,就会停止向接收端的TCP发送报文,直到接收端的TCP发送一个窗体大小非0的ACK报文为止。。。
当接收端向发送端发送ACK应答的时候,假如该应答在传输的路途中丢失了,发送端并没有收到该应答,不再向接收端发送消息;而接收端却认为自己已经做出了回应,一直处在等待的状态中。此时这种情况就是传说中的"死锁"
为了解决上述的"死锁现象",TCP中存在一个持续计时器。启动后,在未超时期间,若收到了接收端的非0窗体的通知,则停止该计时器;若该持续计时器超时了,则发送TCP就发送一个特殊的探測报文段,该报文段仅包括1B的新数据,该报文不须要确认。探測报文的作用在于提醒对方(目的能够记录在数据部分),重传上次发送方发送的那个ACK报文(即那个非0值窗体的报文)。
注意:TCP规定,接收窗体的rwnd=0,也必须接收这三种报文段:零窗体探測报文段、确认报文段和携带紧急数据的报文段。
3.保活计时器(Keeplive Timer),防止两端的TCP在连接期间长时间处于空暇状态。一般是server设置的计时器,超时通常设置为2h,当server超过了2h还没有收到客户的任何信息,server就向客户发送过一个探測报文段,若连续发送了10个探測报文段(每个75s一个)还没有响应,就觉得客户出了故障,直接终止这个连接。
4.时间等待计时器(Time-Wait timer),超时时间=2MSL,max segment lifetime,这个计时器有两个作用:
1).保证在2MSL时间内,server端可以收到最后一个ACK;
2).可以保证之前某些在网络中滞留非常久的发给server的报文不会在本次连接连接关闭后再去骚扰server。
值得注意的是,最后两次挥手期间,启动了两种计时器,server向client发送FIN后启动重传计时器;client收到FIN后,向server发送ACK,同一时间也启动Time-Wait计时器(时间长度为2MSL)。至于2*MSL在TCP的状态中有提到
当然啦TCP的内容远不止这些,有兴趣的童鞋再参考谢希仁的<<计算机网络>>吧~~~~