网络协议---TCP---三次握手四次挥手

MY_网络协议—IP头和TCP头

三次握手流程:

在这里插入图片描述

三次握手期间的3个包不包含数据 但是依旧要消耗一个序号
三次分别为:SYN包			SYN+ACK包			ACK包

TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态;
TCP客户进程也是先创建传输控制块TCB,然后向服务器发出连接请求连接SYN报文。


TCP规定,SYN、ACK、FIN报文段即使不携带数据,也要消耗一个序号。

四次挥手流程:(双方均可主动断开,以客户端主动关闭为例)

在这里插入图片描述

连接状态:客户端和服务器双向通道均生效
CLOSE-WAIT(关闭等待):TCP服务器通知高层的应用进程,客户端→服务器方向关闭  而服务器→客户端还有效+发送数据
FIN-WAIT-2:S→C单向通道 + 单向传输
//从图上开服务器比客户端早一点结束TCP连接

TCP细节设定解释:

1、三次握手 对应 四次挥手的原因:
同样是2组请求(SYN/FIN)+确认(ACK)
而连接时可以将两个ACK和SYN合并
断开时:TCP是双向发送,一端发送完毕时发送FIN,另一端确认ACK;此时另一端可能还有数据,要等数据发送完了才能发送FIN👉不能合并

2、TCPIP断开连接时主动关闭方要等待2MSL时间(TIME_WAIT状态, 2~4分钟左右)才能进入CLOSE状态:
假定网络不稳定,client发送的ACK丢失👉Server没有收到ACK,将不断重复发送FIN片段
client不能自顾自关闭,必须确认server收到了ACK,需要在TIME_WAIT状态等待2MSL时间,若期间收到FIN则发送ACK并重新等待2MSL时间
//2MSL是两倍的MSL(Maximum Segment Lifetime)。
//MSL指一个报文在网络中最大的存活时间,超出则丢弃,2MSL就是一个发送和一个回复所需的最大时间。
//如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

3、若改为需要两次握手,可能发生死锁
假定C给S发送SYN,S收到并发送了ACK 👉	S认为连接成功建立,开始发送数据。但(限时内)得不到C的ACK则重复发送;
									一旦该ACK丢失则C认为连接失败👉等待ACK + 忽略s的信息

4、连接建立后一旦客户端突然出现故障了怎么办?
TCP还设有一个保活计时器。
服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,
若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。
若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。


5、三次连接中能不能省去第三次连接(发起者的ACK)
主要防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误
一旦C发送的第一个SYN在网络中滞留(未丢失)👉C认为S没收到并重发SYN
										在连接完成后第一个SYN(应该是失效的)被S接受👉两次握手机制下会建立连接👉出错+浪费资源
										
										而三次握手机制下延迟的SYN导致S发送ACK,但客户端不会ACK👉没有连接。解决这个问题

补充:
a. 默认情况下(不改变socket选项),当你调用close( or closesocket,以下说close不再重复)时,如果发送缓冲中还有数据,TCP会继续把数据发送完。
b. 发送了FIN只是表示这端不能继续发送数据(应用层不能再调用send发送),但是还可以接收数据。
c. 应用层如何知道对端关闭?通常,在最简单的阻塞模型中,当你调用recv时,如果返回0,则表示对端关闭。在这个时候通常的做法就是也调用close,那么TCP层就发送FIN,继续完成四次握手。如果你不调用close,那么对端就会处于FIN_WAIT_2状态,而本端则会处于CLOSE_WAIT状态。这个可以写代码试试。
d. 在很多时候,TCP连接的断开都会由TCP层自动进行,例如你CTRL+C终止你的程序,TCP连接依然会正常关闭,你可以写代码试试。

TIME_WAIT

TIME_WAIT状态所带来的影响:

当某个连接的一端处于TIME_WAIT状态时,该连接将不能再被使用。事实上,对于我们比较有现实意义的是,这个端口将不能再被使用。
某个端口处于TIME_WAIT状态(其实应该是这个连接)时,这意味着这个TCP连接并没有断开(完全断开),如果你bind这个端口,就会失败。
对于服务器而言,如果服务器突然crash掉了,那么它将无法再2MSL内重新启动,因为bind会失败。
解决这个问题的一个方法就是设置socket的SO_REUSEADDR选项。这个选项意味着你可以重用一个地址。

对于TIME_WAIT的插曲:

当建立一个TCP连接时,服务器端会继续用原有端口监听,同时用这个端口与客户端通信。而客户端默认情况下会使用一个随机端口与服务器端的监听端口通信。有时候,为了服务器端的安全性,我们需要对客户端进行验证,即限定某个IP某个特定端口的客户端。客户端可以使用bind来使用特定的端口。对于服务器端,当设置了SO_REUSEADDR选项时,它可以在2MSL内启动并listen成功。但是对于客户端,当使用bind并设置SO_REUSEADDR时,如果在2MSL内启动,虽然bind会成功,但是在windows平台上connect会失败。而在linux上则不存在这个问题。(我的实验平台:winxp, ubuntu7.10)

要解决windows平台的这个问题,可以设置SO_LINGER选项。SO_LINGER选项决定调用close时TCP的行为。SO_LINGER涉及到linger结构体,如果设置结构体中l_onoff为非0,l_linger为0,那么调用close时TCP连接会立刻断开,TCP不会将发送缓冲中未发送的数据发送,而是立即发送一个RST报文给对方,这个时候TCP连接就不会进入TIME_WAIT状态。如你所见,这样做虽然解决了问题,但是并不安全。通过以上方式设置SO_LINGER状态,等同于设置SO_DONTLINGER状态。

断开连接时的意外:

这个算不上断开连接时的意外,当TCP连接发生一些物理上的意外情况时,例如网线断开,linux上的TCP实现会依然认为该连接有效,而windows则会在一定时间后返回错误信息。这似乎可以通过设置SO_KEEPALIVE选项来解决,不过不知道这个选项是否对于所有平台都有效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值