socket keepalive理解
java socket编程中有个keepalive选项,看到这个选项经常会误解为长连接,不设置则为短连接,实则不然。
socket连接建立之后,只要双方均未主动关闭连接,那这个连接就是会一直保持的,就是持久的连接。keepalive只是为了防止连接的双方发生意外而通知不到对方,导致一方还持有连接,占用资源。
其实这个选项的意思是TCP连接空闲时是否需要向对方发送探测包,实际上是依赖于底层的TCP模块实现的,java中只能设置是否开启,不能设置其详细参数,只能依赖于系统配置。
首先看看源码里面是怎么说的
源码的意思是,如果这个连接上双方任意方向在2小时之内没有发送过数据,那么tcp会自动发送一个探测探测包给对方,这种探测包对方是必须回应的,回应结果有三种:
1.正常ack,继续保持连接;
2.对方响应rst信号,双方重新连接。
3.对方无响应。
这里说的两小时,其实是依赖于系统配置,在linux系统中(windows在注册表中,可以自行查询资料),tcp的keepalive参数
net.ipv4.tcp_keepalive_intvl = 75 (发送探测包的周期,前提是当前连接一直没有数据交互,才会以该频率进行发送探测包,如果中途有数据交互,则会重新计时tcp_keepalive_time,到达规定时间没有数据交互,才会重新以该频率发送探测包)
net.ipv4.tcp_keepalive_probes = 9 (探测失败的重试次数,发送探测包达次数限制对方依旧没有回应,则关闭自己这端的连接)
net.ipv4.tcp_keepalive_time = 7200 (空闲多长时间,则发送探测包)
为了能验证所说的,我们来进行测试一下,本人测试环境是客户端在本地windows上,服务端是在远程linux上,主要测试服务器端向客户端发送探测包(客户端向服务端发送是一样的原理)。
首先需要装一个抓包工具,本人用的wireshark;
然后修改一下tcp_keepalive_time系统配置,改成1分钟,2小时太长了,难等,其余配置不变。修改方法:执行sysctl -w net.ipv4.tcp_keepalive_time=60进行修改,执行sysctl -p刷新配置生效;
最后写一个服务器端和一个客户端,分别启动。
服务器端代码如下(java8):
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket; public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(12345);
while (true) {
Socket socket = ss.accept();
new Thread(() -> {
try {
socket.setKeepAlive(true);
socket.setReceiveBufferSize(8 * 1024);
socket.setSendBufferSize(8 * 1024);
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
try {
byte[] bytes = new byte[1024];
while (is.read(bytes) > -1) {
System.out.println(System.currentTimeMillis() + " received message: " + new String(bytes, "UTF-8").trim());
os.write("ok".getBytes("UTF-8"));
os.flush();
bytes = new byte[1024];
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (!socket.isInputShutdown()) {
socket.shutdownInput();
}
if (!socket.isOutputShutdown()) {
socket.shutdownOutput();
}
if (!socket.isClosed()) {
socket.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
}
客户端代码如下:
public class Client {
public static void main(String[] args) throws IOException, InterruptedException {
Socket socket = new Socket("192.168.16.84", 12345);
socket.setKeepAlive(true);
socket.setSendBufferSize(8192);
socket.setReceiveBufferSize(8192);
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
os.write("get test-key".getBytes("UTF-8"));
os.flush();
Thread.sleep(155 * 1000L);
os.write("get test-key".getBytes("UTF-8"));
os.flush();
byte[] bytes = new byte[1024];
while (is.read(bytes) > -1) {
System.out.println(System.currentTimeMillis() + " received message: " + new String(bytes, "UTF-8").trim());
bytes = new byte[1024];
}
if (!socket.isOutputShutdown()) {
socket.shutdownOutput();
}
if (!socket.isInputShutdown()) {
socket.shutdownInput();
}
if (!socket.isClosed()) {
socket.close();
}
}
}
分别启动服务端和客户端之后,抓包工具抓到的数据:
可以看到,60秒时服务器发送了探测包,探测客户端是否正常,客户端正常响应了,之后以tcp_keepalive_intvl(75秒)的周期进行发送,可以看到135秒又进行发送了探测包。
但是因为我们客户端的代码是在155秒重新发送了数据,所以需要继续空闲60秒,直到215秒才继续发送探测包,后续没有数据交互,所以还是以75秒间隔频率进行发送探测包。从抓包的数据上很容易看出来。
keepalive默认是关闭的,下面我们把服务器端的socket.setKeepAlive(true)一行注释掉的抓包结果:
可以看到服务器端没有向客户端发送探测包,其实客户端设置了socket.setKeepAlive(true),客户端在7355(7200+155)秒时应该会向服务器发送探测包(我把程序挂了2小时。。。结果如下)
验证无误。
socket keepalive理解的更多相关文章
- linux中socket的理解
对linux中socket的理解 一.socket 一般来说socket有一个别名也叫做套接字. socket起源于Unix,都可以用“打开open –> 读写write/read –> ...
- Socket 的理解及实例
Socket 的理解及实例Socket 的理解TCP/IP要想理解socket首先得熟悉一下TCP/IP协议族, TCP/IP(Transmission Control Protocol/Intern ...
- php socket 简单理解
以下内容转自:https://www.cnblogs.com/loveyoume/p/6076101.html 和 https://www.cnblogs.com/WuNaiHuaLuo/p/6107 ...
- 对socket的理解
要想理解socket,就得先熟悉TCP/IP协议族,TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,定义了主机如 ...
- python socket 的理解(1)
前言 socket的用法简单,但里面的概念有点模糊,记录自己本人的一点理解. socket层结构图 注意,从此图中看出socket处于tcp和应用层之间.那么它代表啥意思呢?简明的说,数据的传输都是底 ...
- linux中socket的理解---4
一.socket 一般来说socket有一个别名也叫做套接字. socket起源于Unix,都可以用“打 开open –> 读写write/read –> 关闭close”模式来操作.So ...
- 对Swoole、Workerman和php自带的socket的理解
为什么php自带的socket不怎么听说,基本都是用swoole,workerman去实现? 1.PHP的socket扩展是一套socket api,仅此而已. swoole,用C实现,它的socke ...
- TCP/IP Socket 的理解
网络由下往上分为:物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. TCP 协议对应于传输层,HTTP 协议对应应用层,Socket 则是对 TCP/IP 协议的封装. ...
- TCP/IP、Http、Socket 简单理解
转自:http://blog.csdn.net/guyan0319 https://blog.csdn.net/guyan0319/article/details/79404216 一. 什么是TCP ...
随机推荐
- html是什么?一个完整的html代码告诉你(完整实例版)
html什么意思?这篇文章主要为大家仔细的解释了HTML文档的一个基础的完整代码,还有具体的实例解释,让大家能一下就看懂HTML的基础结构和用法.下面我们一起来看看吧一.html是什么?点击查看htm ...
- 8、Dockerfile详解
除了init之外,每一个进程都应该是其他进程的子进程(init是内核启动的),当手动启动nginx时,那么这个nginx就以shell子进程存在.当打开一个命令行提示符时,这个就相当于在运行一个she ...
- SAP 应收票据处理之贴现流程和配置
特殊总账的应收票据处理是通过特殊总账标识实现的,特殊总账标识为W.在配置特殊总账时候,可以通过下面路径,定义特殊总账标识对应的备选科目.
- Mac OS 挂载 EFI 引导分区
正如Windows下的EFI分区一样在资源管理器中默认不显示EFI引导分区(即ESP分区),Mac OS也是如此,为了安全嘛,不让用户随意操作. 那么怎么挂载显示出来呢? 命令转自 https://b ...
- python自动化测试常用断言的使用方法
自动化测试中寻找元素并进行操作,如果在元素好找的情况下,大家就可以较熟练地编写用例脚本了,但光进行操作可能还不够,有时候也需要对预期结果进行判断. 下面介绍几个常用断言的使用方法,可以一定程度上帮助大 ...
- Mac 下eclipse安装Lombok插件
在官网下载最新版本的 JAR 包. 将 lombok.jar 放在eclipse安装目录下,和 eclipse.ini 文件平级的. 注意,mac操作系统下eclipse的安装路径下有两个eclips ...
- DataNitro安装配置
必须安装python2,并配置环境变量,第一次安装时没有安装python,第一次打开可以使用,后来就打不开了,卸载重装也不行,安装Python2之后才可以. 按步骤安装就可以 不支持WPS
- 2018-2019-2 20175317 实验一《Java开发环境的熟悉》实验报告
实验一<Java开发环境的熟悉> 一.实验内容及步骤 实验内容: (一)实验一Java开发环境的熟悉-1 参考实验要求 建立"自己学号exp1"的目录 在"自 ...
- jdbc、jpa、spring data jpa、hibernate、mybatis之间的关系及区别
基础概念 jdbc(Java DataBase Connectivity)是java连接数据库操作的原生接口.JDBC对Java程序员而言是API,对实现与数据库连接的服务提供商而言是接口模型.作为A ...
- tomcat发布项目如何通过域名直接访问
首先在服务器中找到tomcat安装后的文件夹,进入到conf目录下,找到server.xml文件 打开并修改,修改如下: 第一步:修改port,该值默认为8080,将其修改为80 第二步:修改defa ...