java socket 长连接 心跳包

首先先说说心跳包在socket连接中的意义:
通过socket连接的双方为了保证在一段时间未发消息不被防火墙断开连接或者使对方及时知道自己是否已经断线而定期给对方发送的某些特殊标识字符,这个字符可以根据双方自定义,没有实际的通讯意义。
而定制的时间也是双方协商后定制的。

首先设置socket的一些属性:

//表示底层的TCP 实现会监视该连接是否有效。默认值为 false, 表示TCP 不会监视连接是否有效, 不活动的客户端可能会永远存在下去, 而不会注意到服务器已经崩溃。(当连接处于空闲状态(连接的两端没有互相传送数据) 超过了 2 小时时, 本地的TCP 实现会发送一个数据包给远程的 Socket. 如果远程Socket 没有发回响应, TCP实现就会持续尝试 11 分钟, 直到接收到响应为止. 如果在 12 分钟内未收到响应, TCP 实现就会自动关闭本地Socket, 断开连接. 在不同的网络平台上, TCP实现尝试与远程Socket 对话的时限有所差别.)
  if(!socket.getKeepAlive()) socket.setKeepAlive(true);   
//默认值为 false。为 true 时, 表示支持发送一个字节的 TCP 紧急数据. Socket 类的 sendUrgentData(int data) 方法用于发送一个字节的 TCP紧急数据。 为 false的这种情况下, 当接收方收到紧急数据时不作任何处理, 直接将其丢弃. 如果用户希望发送紧急数据, 应该把 OOBINLINE 设为 trueif(!socket.getOOBInline())socket.setOOBInline(true);

心跳包的写法:

    private Thread thread;//循环发送心跳包的线程
    private Socket socket;//与服务器建立连接的socket对象
    private OutputStream outputStream;//输出流,用于发送心跳

    public void startThreadSocket() {
        try {
            if(!socket.getKeepAlive()) socket.setKeepAlive(true);//true,若长时间没有连接则断开
            if(!socket.getOOBInline())socket.setOOBInline(true);//true,允许发送紧急数据,不做处理
            outputStream = socket.getOutputStream();//获得socket的输出流
            final String socketContent = "[这里为与服务器协商的特殊字符串,用于识别是发送的心跳信息]" + "\n";
            thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        try {
                            Thread.sleep(20 * 1000);//20s发送一次心跳
                            outputStream.write(socketContent.getBytes("UTF-8"));
                            outputStream.flush();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
            thread.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

心跳包的写法很简单,和服务器商定特殊字符串,接收后不做处理。定时发送,然后设置一下socket的属性就行了。

关于socket的其他属性设置:

TCP_NODELAY: 表示立即发送数据.

SO_RESUSEADDR: 表示是否允许重用Socket 所绑定的本地地址. SO_TIMEOUT: 表示接收数据时的等待超时数据. SO_LINGER: 表示当执行Socket 的 close()方法时, 是否立即关闭底层的Socket. SO_SNFBUF: 表示发送数据的缓冲区的大小. SO_RCVBUF: 表示接收数据的缓冲区的大小. SO_KEEPALIVE: 表示对于长时间处于空闲状态的Socket , 是否要自动把它关闭. OOBINLINE: 表示是否支持发送一个字节的TCP 紧急数据.
if(!socket.getTcpNoDelay()) socket.setTcpNoDelay(true);//关闭缓冲区,及时发送数据;默认false,打开缓冲区;先放在缓冲区, 等缓存区满了再发出. 发送完一批数据后, 会等待接收方对这批数据的回应, 然后再发送下一批数据
if(!socket.getResuseAddress())socket.setResuseAddress(true);

//当接收方通过Socket 的close() 方法关闭Socket 时, 如果网络上还有发送到这个Socket 的数据, 那么底层的Socket 不会立即释放本地端口,而是会等待一段时间,确保接收到了网络上发送过来的延迟数据, 然后再释放端口。Socket接收到延迟数据后,不会对这些数据作任何处理。socket接收延迟数据的目的是,确保这些数据不会被其他碰巧绑定到同样端口的新进程接收到。

方法必须在Socket还没有绑定到一个本地端口之前调用,否则执行socket.setResuseAddress(true) 方法无效. 因此必须按照以下方式创建Socket对象, 然后再连接远程服务器 。

更多的属性解释就不一一列举了。

    原文作者:chailongger
    原文地址: https://blog.csdn.net/chailongger/article/details/80548944
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞