网络学习-传输层TCP协议(连接管理机制)

TCP提供面向有链接的可靠性传输 ,面向连接是指在数据通信开始之前,先做好两端之间的准备工作。
这个准备工作是指:通过TCP首部发送一个SYN包作为建立连接的请求,这个请求等待服务端确认应答。也就是要等待服务端关于这个请求的回信。如果对端发来确认应答,则认为可以进行数据通信,如果对端的确认应答未收到,就不会进行数据通信。此外,在数据通信结束还有断开连接的处理。(FIN包)。


三次握手&&四次挥手

TCP中,发送第一个SYN包的一方叫做客户端,接受SYN包的一端叫做服务端,

**建立一个 TCP连接需要发送三个包,这个过程叫做 “三次握手”。
断开TCP连接,需要发送四个包,这个过程叫做“ 四次挥手 ”。**

一个连接的建立与断开,正常过程至少需要来回发送7个包才能完成。

这里写图片描述
这里写图片描述
这里写图片描述

服务端状态转化:

[CLOSED -> LISTEN] :服务器端调用listen后进入LISTEN状态,
等待客户端连接;

[LISTEN -> SYN_RCVD]: 一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送SYN确认报文.

[SYN_RCVD -> ESTABLISHED] :服务端一旦收到客户端的确认报文, 就进入ESTABLISHED状态, 可以进行读写数据了.

[ESTABLISHED -> CLOSE_WAIT]: 当客户端主动关闭连接(调用close), 服务器会收到结束报文段, 服务器返回确认报文段并进入CLOSE_WAIT;

[CLOSE_WAIT -> LAST_ACK] :进入CLOSE_
WAIT后说明服务器准备关闭连接(需要处理完之前的数据); 当服务器真正调用close关闭连接时, 会向客户端发送FIN, 此时服务器进入LAST_ACK状态, 等待最后一个AC到来(这个ACK是客户端确认收到了FIN)

[LAST_ACK -> CLOSED]: 服务器收到了对FIN的ACK, 彻底关闭
连接.

客户端状态转化:

[CLOSED -> SYN_SENT] :客户端调用connect, 发送同步报文段;

[SYN_SENT -> ESTABLISHED]: connect调用成功, 则进入
ESTABLISHED状态, 开始读写数据;

[ESTABLISHED -> FIN_WAIT_1] :客户端主动调用close时, 向服
务器发送结束报文段FIN, 同时进入FIN_WAIT_1;

[FIN_WAIT_1 -> FIN_WAIT_2] :客户端收到服务器对结束报文段
的确认, 则进入FIN_WAIT_2, 开始等待服务器的结束报文段;

[FIN_WAIT_2 -> TIME_WAIT]: 客户端收到服务器发来的结束报
文段, 进入TIME_WAIT, 并发出LAST_ACK;

[TIME_WAIT -> CLOSED] 客户端要等待一个2MSL(Max
Segment Life, 报文最大生存时间)的时间, 才会进入
CLOSED状态

以上就是三次握手,四次挥手的图解。中间部分是数据传输的简单过程。(不考虑丢包和重传)


三次握手与四次挥手余留问题

1)一次握手行不行?

答案:肯定不行。一次握手意味着就只发送一个SYN数据包,这个数据包只是发送出去了,对端收到没收到,无法知道,这跟UDP差不多了。

2)两次握手行不行?
答案:不行。按照上面图解,两次握手意味着发送方发了一个SYN请求建立连接的同步报文段,对端一旦监听到连接请求(SYN同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送ACK确认报文并携带对端的SYN同步报文段,希望得到发送方的回应(ACK)。

当发送方收到确认报文ACK,此时他进入ESTABLISHED 状态,认为连接已经建立好了。但是,此时对端(服务端)还在SYN_RCVD]状态,认为连接还没有建立好。

危害:

此时,如果是服务端还没有建立好连接,而客户端认为连接建立工作已经完成,就会导致数据丢包的问题,而丢包又会触发超时重传机制,重复发送数据包,从而
引起网络拥塞等一系列问题。

而如果服务器认为建立好了连接,客户端还没有连接成功,则客户端就会多次发送SYN数据包,当请求太多时就会,服务器上的无效连接就会越来越多。导致处理有效连接的个数越来越少,资源被浪费。容易造成服务器崩溃。

当SYN过多,还会引起SYN洪水。

3)三次握手的好处

(1)服务器安全,即使没有收到ACK,也不会产生很多无效连接。
(2)成功率高,经过三次握手双方都可以建立成功。
(3)对客户端影响小,当没有收到确认ACK,也会触发RST标志位,重新建立连接。

4)四次握手可以吗?
答案:其一:没有必要。三次握手连接就已经建立好了。四次没有必要。
其二:四次握手会将危害转移到服务器,危害见问题2答案。

5)为什么需要四次挥手
答案:连接的断开,需要双方的请求与确认。否则可能会处于中间态,即不能正常的发送接收数据,连接也没有断开,在那浪费资源。

6)四次挥手有没有可能失败?
答:有可能失败。

当TIME_WAIT状态下发送的ACK丢失,服务器端的LAST_ACK时刻设定的重传定时器超时,发送重传的FIN,很不幸,这个FIN也丢失,主动关闭方在 TIME_WAIT状态等待2MSL没收到任何报文段,进入CLOSED状态,当此时被动关闭方并没有收到最后的ACK。所以即使要主动关闭方在 TIME_WAIT状态下停留2MSL,也不一定表示四次握手关闭就一定正常完成


理解TIME_WAIT状态

现在做一个测试,首先启动server,然后启动client,然后用Ctrl-C使server终止,这时马上再运行server, 结果是:

这里写图片描述

这是因为,虽然server的应用程序终止了,但TCP协议层的连接并没有完全断开,因此不能再次监 听同样的server端口. 我们用可以用netstat命令查看一下状态。

netstat -apn | grep 8081

TCP协议规定,主动关闭连接的一方要处于TIME_ WAIT状态,等待两个MSL(maximum segment lifetime)的时间后才能回到CLOSED状态.我们使用Ctrl-C终止了server, 所以server是主动关闭连接的一方, 在TIME_WAIT期间仍然不能再次监听同样的server端口;
在客户端按下ctrl+c,再来查看一下状态。可以看到进入TIME_WAIT状态。
这里写图片描述

MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同, 在 Centos7上默认配置的值是60s;可以通过下面命令 查看msl的值;

 cat /proc/sys/net/ ipv4/tcp_fin_timeout
TIME_WAIT的时间为什么是2MSL?

MSL是TCP报文的最大生存时间, 因此TIME_WAIT持续存在2MSL的话就能保证在两个传输方向上的尚未被接收或迟到的报文段已经消失,(否则重启服务器可能收到来自上一个进程的迟到的数据, 但是这种数据很可能是错误的);同时也是在理论上保证最后一个报文可靠到达(假设最后一个ACK丢失, 那么服务器会再重发一个FIN. 这时虽然客户端的进程不在了, 但是TCP连接还在, 仍然可以重发LAST_ACK);
在server的TCP连接没有完全断开之前不允许重新监听, 某些情况下可能是不合理的

例如:
服务器需要处理非常大量的客户端的连接(每个连接的生存时间可能很短, 但是每秒都有很大数量的客户端来请求).这个时候如果由服务器端主动关闭连接(比如某些客户端不活跃, 就需要被服务器端主动清理掉), 就会产生大量TIME_WAIT连接.由于我们的请求量很大, 就可能导致TIME_WAIT的连接数很多, 导致服务器的端口不够用, 无法处理新的连接.

为了避免上情况,我们可以使用setsockopt()设置socket描述符的 选项SO_REUSEADDR为1, 表示允许创建端口号相同但IP地址不同的多个socket描述符在
server代码的socket()和bind()调用之间插入如下代码:

int opt=1
int setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

这样,即使在TIME_WAIT状态下,服务器关闭也可以立即重启。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值