最近开发中遇到以下:需要客户端建立一个链接,然后服务器端持有这个链接,当有时间变换(如任务的状态改变),需要后端将事件推送给任务对应的责任人。因为博主之前也研究过WebSocket,开发了个简单的聊天室,但是这次这次应用到实际,我就在想TCP的这个长连接在不发生异常的情况下可以维持多久?在思考这个问题时,我就在想Http建立的TCP短连接,是什么时候断开连接的?基于这个问题,我就写了个简单的测试用例,通过tcpdump来抓包,对长连接和短连接进行对比分析。
下面我们来简单的介绍下长连接和短连接的概念。
首先是TCP,三次握手建立连接,四次挥手释放连接,示意图如下:
短连接就如上图所示,数据传输完成后,一般由客户端发起释放连接的信号,也可以看到,短连接是进行一次请求,请求结束后断开连接,那就回到上面令博主疑惑的问题了,建立连接我们都知道,Http请求到达服务器,就会立刻建立TCP连接,那是什么时候断开的呢?是服务器return了结果后立刻结束么,还是别的情况,别急,后面我们会来给大家讲解。
长连接,和短连接最简单最直接的区别就是,他是为了服务器和客户端间的一个频繁的交互,之前的浏览器端定时的ajax轮询会消耗大量的资源,现在已经很少有人使用了;另一个,长连接比短连接更大的一个优势就是,服务器端可以维护和客户端建立的这个TCP通信的channel,这样就可以让服务器主动的给客户端发送数据,也等同于实现了全双工通信,这个也是相比ajax轮询更大的一个优势,可以实现事件的实时通知。
基于上面所讲的,我们来分析下长连接和短连接的优缺点:
- 长连接可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间。对于频繁请求资源的客户来说,较适用长连接;
- 长连接如果不主动关闭,这个连接会长久的存在,并且如果长连接滥用,或者不加任何限制,会导致连接数过多,会对服务器的产生较大的压力,因此长连接在使用时要慎用,做好评估和限制;
- 短连接对于服务器来说管理较为简单,存在的连接都是有用的连接,不需要额外的控制手段。但如果客户请求频繁,将在TCP的建立和关闭操作上浪费时间和带宽。
下面,我们就开始使用tcpdump来进行抓包来分析上面让我们疑惑的两个问题,首先,我们启动服务端,长连接就是我们使用的WebSocket,短连接就是一个简单的无业务逻辑的一个接口,
在电脑上启动tcpdump,命令如下,其中-w指定抓到的包的输入路径,如果没有-w的话,会将包输出到shell窗口:
sudo tcpdump -i lo0 -w /tmp/tcpdump/1.pcap port 8080
tcpdump命令的详解大家可以参考这篇博客:https://www.jianshu.com/p/b281964a8459
本文为了更好的分析,将日志输出到文件,并使用wireshark软件进行分析,数据包如下:
从中我们可以看到,红框中的为TCP连接建立的过程,红色箭头是创建WebSocket的请求,后面我们可以看到,数据反而发送就是TCP和WebSocket协议了,后面客户端和服务端之间的数据发送就无须建立TCP连接了,这和我们预料的是一致。
但是困扰我们的一个问题:长连接在不发生异常的情况下可以维持多久?经过博主的测试,4个小时是没有任何问题的,具体多久就没有继续测试啦。。。而且,这个连接的保持应该有客户端来进行,可以定时的检查连接的状态,如果链接断开,可以重新建立连接,这样可以保证连接的畅通,事件可以及时的有服务端推送到客户端。
下面我们来分析短连接,大家也也在思考一下困扰我们的问题:TCP短连接是什么时候断开的?结果可能和你预期的不太一样,下面我们一起来看下:
接口代码如下:
@GetMapping("/create")
public String onCreate(){
log.info("---------1111");
return "OK";
}
下面就是直接在浏览器上输入url,按下回车键,并请求五次,每次的时间间隔为3s左右,wireshark分析得到的数据包如下:
由上图我们可以看到,第一次调用接口时,创建了TCP连接,但是之后的每隔三秒的再次调用,是没有重新创建TCP连接的,而是使用了之前已经创建好的连接,最后,在经过一段时间后,TCP断开连接,因为wireshark中没有时间,我们截取原始的数据包来展示TCP断开连接的时间,
上图是一次Http请求的所有报文,也是一次TCP连接的建立和断开,从中我们可以看到,连接的建立和数据的发送很快就结束了,但是连接的断开时在数据发送结束差不多45s开始的,由客户端发送,ack 116,服务器端真正断开连接是在约一分钟后。
是不是和你预料的结果不太一致呢?但是为什么会导致这个结果呢,大家看下面这张截图:
之前,在http/1.0中,一个服务器发送完http响应后,会断开TCP连接。但是这样每次请求都会重新建立和断开TCP连接,开销太大。所以虽然标准中没有设定,某些服务器对Connection:keep-alive的Header进行了支持。意思是说,完成这个HTTP请求后,不要断开HTTP请求使用的TCP连接。这样的好处是连接可以被重复使用,之后发送HTTP请求的时候就不用再重新建立TCP连接了。这也符合我们刚才截图中的结果,这样,如果我们频繁的请求,Http短连接也是可以满足需求的,可见在我们开发中,有很多问题都有人为我们考虑到了。
我们可以做一个实验,修改请求头中的Connection,值改为close,这就需要我们在postMan中调用,结果如下图所示:
可以看到,连接的建立和断开非常的快,这也符合我们最开始的设想。
讲到这里,大家对长连接和短连接应该都很明白了,迷惑我们的两个问题也都很清楚了,希望本文能对大家有所帮助,如果有什么疑问,欢迎评论留言交流。
最后,原创不易,喜欢的话请点赞支持,谢谢。