VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章正在更新中...)https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_11931267.html开源组件及数据库技术(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_2276111.htmlTCP是是一个面向连接的协议,无论哪一方发送数据之前,都必须在双方之间建立一条连接。
一、建立连接
建立TCP连接时,要经历这样的流程:
- ① 请求端(通常称为客户)发送一个SYN段指明客户打算连接的服务器的端口,以及初始序号(ISN)。这个SYN段为报文段1。
- ② 服务器发回包含服务器的初始序号的SYN报文段(报文段2)作为应答。同时,将确认序号设置为客户的ISN加1对客户的SYN报文段进行确认。一个SYN将占用一个序号。
- ③客户必须将确认序号设置为服务器的ISN加1以对服务器的SYN报文段进行确认(报文段3)。
这个过程也称为三次握手。
此处之所以还要再发送一次确认是为了,防止已失效的连接请求报文段突然又传到了B,因而产生错误。
已失效的报文段:正常情况下:A发出连接请求,但因为丢失了,故而不能收到B的确认。于是A重新发出请求,然后收到确认,建立连接,数据传输完毕后,释放连接,A发了2个,一个丢掉,一个到达,没有“已失效的报文段”
但在某种情况下,A的第一个在某个节点滞留了,延误到达,本来这是一个早已失效的报文段,但是在A发送第二个,并且得到B的回应,建立了连接以后,这个报文段竟然到达了,于是B就认为,A又发送了一个新的请求,于是发送确认报文段,同意建立连接,假若没有三次的握手,那么这个连接就建立起来了(有一个请求和一个回应),此时,A收到B的确认,但A知道自己并没有发送建立连接的请求,因为不会理睬B的这个确认,于是呢,A也不会发送任何数据,而B呢却以为新的连接建立了起来,一直等待A发送数据给自己,此时B的资源就被白白浪费了。但是采用三次握手的话,A就不发送确认,那么B由于收不到确认,也就知道并没有要求建立连接。
二、连接终止
建立一个连接需要三次握手,而终止一个连接要经过4次挥手。这由TCP的半关闭(half-close)造成的。既然一个TCP连接是全双工(即数据在两个方向上能同时传递),因此每个方向必须单独地进行关闭。这原则就是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。当一端收到一个FIN,它必须通知应用层另一端已经终止了那个方向的数据传送。发送FIN通常是应用层进行关闭的结果。
B收到连接释放报文段后就立即发送确认,然后就进入close-wait状态,此时TCP服务器进程就通知高层应用进程,因而从A到B的连接就释放了。此时是“半关闭”状态。即A不可以发送给B,但是B可以发送给A。
此时,若B没有数据报要发送给A了,其应用进程就通知TCP释放连接,然后发送给A连接释放报文段,并等待确认。
A发送确认后,进入time-wait,注意,此时TCP连接还没有释放掉,然后经过时间等待计时器设置的2MSL后,A才进入到close状态。为什么要等待呢?
- ①、为了保证A发送的最后一个ACK报文段能够到达B。即最后这个确认报文段很有可能丢失,那么B会超时重传,然后A再一次确认,同时启动2MSL计时器,如此下去。如果没有等待时间,发送完确认报文段就立即释放连接的话,B就无法重传了(连接已被释放,任何数据都不能出传了),因而也就收不到确认,就无法按照步骤进入CLOSE状态,即必须收到确认才能close。
- ②、防止“已失效的连接请求报文段”出现在连接中。经过2MSL,那些在这个连接持续的时间内,产生的所有报文段就可以都从网络中消失。即在这个连接释放的过程中会有一些无效的报文段滞留在楼阁结点,但是呢,经过2MSL这些无效报文段就肯定可以发送到目的地,不会滞留在网络中。这样的话,在下一个连接中就不会出现上一个连接遗留下来的请求报文段了。
可以看出:B结束TCP连接的时间比A早一点,因为B收到确认就断开连接了,而A还得等待2MSL.
三、TCP的状态迁移图
客户端的状态可以用如下的流程来表示:
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
服务器的状态可以用如下的流程来表示:
CLOSED->LISTEN->SYN_RCVD->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
FIN_WAIT_2:在这个状态下,应用程序还有接受数据的能力,但是已经无法发送数据。
RST是另一种关闭连接的方式,应用程序应该可以判断RST包的真实性,即是否为异常中止。而同时打开和同时关闭则是两种特殊的TCP状态,发生的概率很小。
上图还有一些其他的状态迁移,这些状态迁移针对服务器和客户端两方面的总结如下:
1)LISTEN->SYN_SENT,对于这个解释就很简单了,服务器有时候也要打开连接的嘛。
2)SYN_SENT->SYN_RCVD,服务器和客户端在SYN_SENT状态下如果收到SYN数据报,则都需要发送SYN的ACK数据报并把自己的状态 调整到SYN收到状态,准备进入ESTABLISHED。
3)SYN_SENT->CLOSED,在发送超时的情况下,会返回到CLOSED状态。
4)SYN_RCVD->LISTEN,如果受到RST包,会返回到LISTEN状态。
5)SYN_RCVD->FIN_WAIT_1,这个迁移是说,可以不用到ESTABLISHED状态,而可以直接跳转到FIN_WAIT_1状态并等待关闭。