#
#服务器
TCP协议提供可靠的面向链接服务,采用三次握手创建链接。
第一次握手:创建链接时,客户端发送SYN包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到SYN包,向客户端返回ACK(ack=j+1),同时本身也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RCVD状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据,也就是ESTABLISHED状态。 网络
#并发
采用四次挥手断开双向链接。
(1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。
(2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN同样,一个FIN将占用一个序号。
(3) 服务器关闭客户端的链接,发送一个FIN给客户端。
(4) 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。socket
**三次握手**是`TCP/IP`创建链接的确认机制,是客户端和服务器双方要确认对方能收到本身的信息,而**三次握手**是最短路径。 1. 第一次握手:创建链接时,`Client`发送请求报文段(`syn seq=x`),进入`SYN_SENT`状态,等待`Server`确认。 2. 第二次握手:服务器收到,`Server`回复信息给`Client`,包含给客户端的确认信息,和服务器自身的报文信息(`ack=x+1 syn seq=y`),此时服务器进入`SYN_RECV`状态。 3. 第三次握手:客户端收到`SYN+ACK`包,`Client`回复服务器(`ack=y+1`),客户端和服务器进入`ESTABLISHED`(TCP链接成功)状态,完成三次握手。 三次握手完成后,客户端与服务器开始传送数据。
形象比喻ide
- A 向 B 发起创建链接请求:A——>B;
- B 收到 A 的发送信号,而且向A发送确认信息:B——>A;
- A 收到 B 的确认信号,并向B发送确认信号:A——>B。
经过第一次握手,B 知道 A 可以发送数据。经过第二次握手,A 知道 B 能发送数据。
结合第一次握手和第二次握手,A 知道 B 能接收数据。结合第三次握手,B知道A可以接收数据。测试至此,完成了握手过程,A 知道 B 能收能发,B 知道 A 能收能发,通讯链接至此创建。
三次链接是保证可靠的最小握手次数,再屡次握手也不能提升通讯成功的几率,反而浪费资源。ui
**四次挥手**是`TCP/IP`关闭链接的确认机制。 对于一个已经创建的链接,TCP使用改进的三次握手来释放链接(使用一个带有FIN附加标记的报文段)。TCP关闭链接的步骤以下: 1. 第一步:当主机 **A** 的应用程序通知TCP数据已经发送完毕时,TCP向主机B发送一个带有`FIN`附加标记的报文段(FIN表示英文finish)。 2. 第二步:主机 **B** 收到这个`FIN`报文段以后,并不当即用**FIN**报文段回复主机A,而是先向主机A发送一个确认序号**ACK**,同时通知本身相应的应用程序:对方要求关闭链接(先发送ACK的目的是为了防止在这段时间内,对方重传FIN报文段)。 3. 第三步:主机 **B** 的应用程序告诉**TCP**:我要完全的关闭链接,**TCP**向主机 **A**送一个`FIN`报文段。 4. 第四步:主机 **A** 收到这个 `FIN` 报文段后,向主机 **B** 发送一个`ACK`表示链接完全释放。
形象比喻操作系统
- A 向 B 发起请求(fin),表示A没有数据要发送了:A——>B;
- B 向 A 发送信号(ack),知道A要请求断开;
- B 向 A 发送信号(fin),数据接收完成,告知B要关闭链接:B——>A;
- A 向 B 收到信号(fin)向B发送(ack),确认断开:A——>B。
- B 收到确认信号,断开链接,而A在一段时间内没收到B的信号,代表B已经断开了,因而A也断开了链接。至此,完成挥手过程。
2,3次挥手不能合为一次,由于此时 A 虽然再也不发送数据了,可是还能够接收数据,B可能还有数据要发送给A,因此两次挥手不能合并为一次。
挥手次数比握手多一次,是由于握手过程,通讯只须要处理链接。而挥手过程,通讯须要处理数据+链接。code
(1)客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程当中的报文1。
(2) 服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志和SYN标志。所以它表示对刚才客户端SYN报文的回应;同时又标志SYN给客户端,询问客户端是否准备好进行数据通信。
(3) 客户必须再次回应服务段一个ACK报文,这是报文段3。blog
因为TCP链接是全双工的,所以每一个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的链接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP链接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另外一方执行被动关闭。
(1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送(报文段4)
(2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN同样,一个FIN将占用一个序号
(3) 服务器关闭客户端的链接,发送一个FIN给客户端(报文段6)
(4) 客户段发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)
`CLOSED`:这个没什么好说的了,表示初始状态。 `LISTEN`:这个也是很是容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,能够接受链接了。 `SYN_RCVD`:这个状态表示接受到了SYN报文,在正常状况下,这个状态是服务器端的SOCKET在创建TCP链接时的三次握手会话过程当中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特地写了一个客户端测试程序,故意将三次TCP握手过程当中最后一个ACK报文不予发送。所以这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。 `SYN_SENT`:这个状态与SYN_RCVD遥想呼应,当客户端SOCKET执行CONNECT链接时,它首先发送SYN报文,所以也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。 `ESTABLISHED`:这个容易理解了,表示链接已经创建了. `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看到。 `FIN_WAIT_2`: 上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半链接,也即有一方要求close链接,但另外还告诉对方,我暂时还有点数据须要传送给你,稍后再关闭链接。 `TIME_WAIT`:表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后便可回到CLOSED可用状态了。若是FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,能够直接进入到TIME_WAIT状态,而无须通过FIN_WAIT_2状态。 `CLOSING`:这种状态比较特殊,实际状况中应该是不多见,属于一种比较罕见的例外状态。正常状况下,当你发送FIN报文后,按理来讲是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。可是CLOSING状态表示你发送FIN报文后,并无收到对方的ACK报文,反而却也收到了对方的FIN报文。什么状况下会出现此种状况呢?其实细想一下,也不可贵出结论:那就是若是双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的状况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET链接。 `CLOSE_WAIT`: 这种状态的含义实际上是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给本身,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正须要考虑的事情是察看你是否还有数据发送给对方,若是没有的话,那么你也就能够close这个SOCKET,发送FIN报文给对方,也即关闭链接。因此你在CLOSE_WAIT状态下,须要完成的事情是等待你去关闭链接。 `LAST_ACK`:这个状态仍是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
CLOSED->LISTEN->SYN收到 ->ESTABLISHED->CLOSE_WAIT->LAST->ACK->CLOSED
TIME_WAIT状态也称为2MSL等待状态。每一个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime)。它是任何报文段被丢弃前在网络内的最长时间。处理原则:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2MSL。这样可以让TCP有机会在此发送最后一个ACK以防这个ACK丢失(在另外一端发送FIN前提)
可是,在链接处于2MSL等待时,任何迟到返回的报文段将被丢弃。由于处于2MSL等待的、由该插口对(socket pair)定义的链接在这段时间内不能被再用,对于客户程序还好 一些,可是对于服务程序,例如httpd,它老是要使用同一个端口80来进行服务,而在 2MSL时间内,启动httpd就会出现错误(插口被使用)。为了不这个错误,服务器给出了一个平静时间(quit time)的概念,这是说在2MSL时间内,虽然能够从新启动服务器,可是这个服务器仍是要平静等待MSL时间才能进行下一次链接,让后来返回的数据包没有机会影响到发送端,由于返回的包和从新创建的包使用同一个四元组,发送端没法区分这两个包属于不一样链接。(建议MSL时间为2min,不过这个与操做系统有关。)
若是以防已经关闭或异常终止链接而另外一方殊不知道,咱们将这样的TCP链接称为半打开的。这种状态能够经过Keepalive选项来进行发现两一段已经消失。还有一种形式是:本端发送SYN,对端回应ACK+SYN,此时本段不回应ACK。
**当处于半打开状态的一方重启并从新链接后,它将丢失复位前的全部信息,所以它并不知道数据报文段中提到的链接。此时就会返回RST(异常终止要发送RST置位的包)包应答,已关闭这次链接。此时只须要等待MSL时间,由于TCP默认机器重启的时间大于MSL。PIX防火墙和IDS*检测系统均可以假装×××目标发送RST的包去终止异常的TCP链接。(好比限定链接的时间,减小半开链接限制超时时间)当咱们Telnet一个不存在的端口号时,本段立马收到一个拒绝访问的包,这个就是对方发送的RST包致使的。
单方向链路关闭。即TCP链接一端在结束它的发送后还能接收来自另外一端数据的能力。程序调用的是shutdown,而不是close,不过大多数程序都是调用close终止两个方向的链接。
最大报文段长度表示TCP传往另外一端的最大块数据的长度。当创建一个链接时,每一方都受到对方通告的MSS值(MSS选项只能出如今SYN报文中)。若是一方收不到另外一方的MSS值,那么就设为默认的536字节。MSS是最长见的选项字段,还有另外一个选项叫作窗口放大因子(Window*Shift Count便可以发送超大的数据包,即乘以目前窗口的倍数为实际一次发送的数据量。解决高速链路和高速主机普通TCP发包过慢问题。)。还有一些HASH值也会放在Option字段。而防火墙默认则会清掉IP和TCP的Option选项字段。