不管在网上还是书上讲解四次挥手的时候,总是有类似这么一句话:“假设现在客户端发起断开连接请求”,但谁都是既没有明确说服务端也不能,也没有说“假设现在服务端端发起断开连接请求”。
可以的。
最初的HTTP 1.0,接收到来自Client的HTTP Request,服务器发出HTTP Response之后,一次HTTP交易就完成了。
然后呢?
服务器进程(c)就发起断开(Closed)TCP连接的请求。TCP连接通信一共牵扯4个进程:
客户端进程(Client Process)
客户端TCP内核进程(Client Kernel Process)
服务器进程(Server Process)
服务器TCP内核进程(Server Kernel Process)
由于HTTP Response刚发出,服务器就发出Closed TCP Connection的(FIN)请求。
当Client(a)收到HTTP Response之后,即使立马发出Closed TCP Connection的(FIN)请求,也比服务器慢了一步。
客户端的TCP(b)需要ACK Both HTTP Response and Server FIN,并发出Client FIN。
服务器的TCP(d)成功接收,并对接收到的Client FIN发出自己的ACK。
客户端的TCP(b)收到自己的Client FIN的ACK之后,状态机立马切换到Closed。
状态机Closed意味着什么?
意味着Client的Socket、以及Socket关联PCB的所占据的Memory统统释放掉。
服务器的TCP(d)此时的状态为Time_Wait。
意味着服务器的TCP(d)需要等待至少2MSL (Maximum Segment Life)才能释放该Socket(TCP连接关联的)占据的Memory。
通常MSL = 1-2分钟,所以2MSL= 2-4分钟。
如果每断开一个TCP连接,需要至少2分钟才能彻底释放Socket占据的内存。对于服务器来说是一个灾难,不仅会耗尽服务器的Memory资源,还会耗尽服务器可用FD(File Descriptor)。
netstat -ano 在服务器上查询一下TCP连接,会发现大量的TCP连接处于Time_Wait。
此时,服务器内心OS,为什么受伤的总是我?
服务器作为服务全球(Internet)的服务中枢,如果把所有的断开TCP连接的所有扫尾工作都一个人抗,最终受伤的只有自己。
为了不让自己受伤,服务器进程(c)努力不让自己主动发起FIN请求,而是让Client主动发起FIN请求。
即使最终Client滞留在Time_Wait,但是数量并不会很多,充其量几十、上百而已。
而服务器端滞留在Time_Wait,可能在几万、几十万的数量级。
业界看出了Server的窘境,于是在HTTP 1.0添加了一个Connection 的Header。
Connection:Keep-alive
双方如果都支持,表示该TCP连接为长连接,即可用于服务多次HTTP交易。
如果Client在该TCP传输多次HTTP交易之后,完成了用户的请求,由Client进程(a)主动发起FIN请求。
最后的结果是,Client的TCP(b)滞留在Time_Wait,服务器的TCP(d)关联的Socket完全释放。
后来,HTTP1.1默认使用Connection:Keep-alive,即使header里没有。但是,为了兼容HTTP 1.0,通常情况下,HTTP1.1 header里会携带Connection:Keep-alive。
概述
服务器主动关闭TCP连接,关闭TCP连接的扫尾工作一个人抗,千千万万的Client逍遥快活。
Client主动关闭TCP连接,关闭TCP连接的扫尾工作,留给千千万万的Client分担(小菜一碟),服务器彻底脱身而出。集中精力(CPU、Memory)服务来自全球的Client的新的请求!
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...