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小时。。。结果如下)

验证无误。

原文地址:https://www.cnblogs.com/xiao-tao/p/9718017.html

时间: 2024-10-22 16:21:38

socket keepalive理解的相关文章

Socket 的理解及实例

Socket 的理解及实例Socket 的理解TCP/IP要想理解socket首先得熟悉一下TCP/IP协议族, TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,定义了主机如何连入因特网及数据如何再它们之间传输的标准,从字面意思来看TCP/IP是TCP和IP协议的合称,但实际上TCP/IP协议是指因特网整个TCP/IP协议族.不同于ISO模型的七个分层,TCP/IP协议参考模型把所有的TCP/IP系列协议归类

php socket 简单理解

以下内容转自:https://www.cnblogs.com/loveyoume/p/6076101.html 和 https://www.cnblogs.com/WuNaiHuaLuo/p/6107771.html 什么是TCP/IP.UDP? TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的.         UDP(User Data Protoco

linux中socket的理解---4

一.socket 一般来说socket有一个别名也叫做套接字. socket起源于Unix,都可以用“打 开open –> 读写write/read –> 关闭close”模式来操作.Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写 IO.打开.关闭). 说白了Socket是应用层与TCP/IP 协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket

对HTTP、HTTPS、Socket的理解以及三者的关系

HTTP 一.HTTP协议详解 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.目前在WWW中使用的是HTTP/1.0的第六版,HTTP/1.1的规范化工作正在进行之中. http(超文本传输协议)是一个基于请求与响应模式的.无状态的.应用层的协议,常基于TCP的连接方式,HTTP1.1版本中给出一种持续连接的机制,绝大多数的Web开发,都是构建在HTTP协议之上的Web应用. HTTP协议的主要特点可概括如下: 1.支持客户/服务器模式. 2.简单

TCP/IP Socket 的理解

网络由下往上分为:物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. TCP 协议对应于传输层,HTTP 协议对应应用层,Socket 则是对 TCP/IP 协议的封装. 也可以说 TCP/IP 协议是传输层协议,主要解决数据如何在网络中传输,HTTP 是应用层协议,解决如何包装传输的数据. 实际上 Socket 是对 TCP/IP 协议的封装,Socket 本身并不是协议,而是一个调用接口(API),通过 Scoket 我们才能使用 TCP/IP. 所以说 Socket 的出现只是使

Socket 通俗理解

摘自百度知道 TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口.这个就像操作系统会提供标准的编程接口,比如win32编程接口一样,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口.

对socket的理解以及认识

上一遍是对一个聊天项目的笔记,里面socket也涉及的不少.那么socket到底是一个什么东西. 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. 通俗一点来讲,我觉得就是一个连接器,把两者联系起来的一个连接者.好比.Socket的英文原义是“孔”或“插座”.他就相当于是那个插座,连接着来实现不同虚拟机或不同计算机之间的通信. 连接过程:服务器监听 客户端请求 连接确认

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

为什么php自带的socket不怎么听说,基本都是用swoole,workerman去实现? 1.PHP的socket扩展是一套socket api,仅此而已. swoole,用C实现,它的socket是C 库的socket,更加底层可控. workerman,如题主所说,使用PHP实现,那它的socket就是用PHP socket扩展啊.只是对其进行工程化开发,成了一个框架. 2.swoole 框架和 swoole 扩展是不一样的. swoole 框架也可以脱离 swoole 扩展来使用. s

HTTP TCP/IP SOCKET的理解和它们之间的关系

参考网址:http://blog.csdn.net/lemonxuexue/article/details/4485877 http://blog.csdn.net/heyetina/article/details/8056575