socket 如何判断远端服务器的连接状态?连接断开,需重连

fluent-logger-java is a Java library, to record events via Fluentd, from Java application. https://github.com/fluent/fluent-logger-java

使用该sdk过程发现,tcp连接断开之后,该sdk的重连机制无效。

2018-01-26 12:36:25,620 ERROR [org.fluentd.logger.sender.RawSocketSender] - <org.fluentd.logger.sender.RawSocketSender>
java.net.SocketException: Software caused connection abort: socket write error
	at java.net.SocketOutputStream.socketWrite0(Native Method)
	at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
	at java.net.SocketOutputStream.write(SocketOutputStream.java:159)
	at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
	at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
	at org.fluentd.logger.sender.RawSocketSender.flush(RawSocketSender.java:200)
	at org.fluentd.logger.sender.RawSocketSender.send(RawSocketSender.java:188)
	at org.fluentd.logger.sender.RawSocketSender.emit(RawSocketSender.java:158)
	at org.fluentd.logger.sender.RawSocketSender.emit(RawSocketSender.java:140)
	at org.fluentd.logger.sender.RawSocketSender.emit(RawSocketSender.java:135)
	at org.fluentd.logger.FluentLogger.log(FluentLogger.java:101)
	at org.fluentd.logger.FluentLogger.log(FluentLogger.java:86)
	at fluentdDemo.fluentdDemo.main(fluentdDemo.java:90)

查看源码:见RawSocketSender类

private void reconnect() throws IOException {
        if (socket == null) {
            connect();
        } else if (socket.isClosed() || (!socket.isConnected())) {
            close();
            connect();
        }
    }

判断 Socket 远程端连接如果关闭的话,就要重建连接。Socket的类提供了一些已经封装好的方法, 如  isClosed()、isConnected()、isInputStreamShutdown()、isOutputStreamShutdown()等,

在测试时发现,这些方法都是本地端的状态,无法判断远端是否已经断开连接。

有些同学处理类似问题时,通过OutputStream发送一段测试数据,如果发送失败就表示远端已经断开连接,类似ping,但是这样会影响到正常的输出数据,远端无法把正常数据和测试数据分开。

其实,这种方法也是可以的,只不过,不要发送测试数据,直接发送需要发送的数据,一旦失败,就主动close socket,再新建连接,再重新发送就行了。

也有些同学想到通过发送紧急数据,来验证连接状态,见socket类(如下),如果失败,就close socket,再新建连接。

/**
     * Send one byte of urgent data on the socket. The byte to be sent is the lowest eight
     * bits of the data parameter. The urgent byte is
     * sent after any preceding writes to the socket OutputStream
     * and before any future writes to the OutputStream.
     * @param data The byte of data to send
     * @exception IOException if there is an error
     *  sending the data.
     * @since 1.4
     */
    public void sendUrgentData (int data) throws IOException  {
        if (!getImpl().supportsUrgentData ()) {
            throw new SocketException ("Urgent data not supported");
        }
        getImpl().sendUrgentData (data);
    }

可通过如下写法实现:

/**
* 判断是否断开连接,断开返回true,没有返回false
* @param socket
* @return
*/
public Boolean isServerClose(Socket socket){
   try{
    socket.sendUrgentData(0xFF);//发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信
    return false;
   }catch(Exception se){
    return true;
   }
}

前提:对方Socket的SO_OOBINLINE属性没有打开,就会自动舍弃这个字节,而SO_OOBINLINE属性默认情况下就是关闭的

见SocketOptions接口

 /**
     * When the OOBINLINE option is set, any TCP urgent data received on
     * the socket will be received through the socket input stream.
     * When the option is disabled (which is the default) urgent data
     * is silently discarded.
     *
     * @see Socket#setOOBInline
     * @see Socket#getOOBInline
     */
    @Native public final static int SO_OOBINLINE = 0x1003;

当然,我觉得也可以通过定时发送紧急数据来做心跳,确保tcp长连接保活,对方可以不用回应。

测试结果:

这两种方式再连接断开后的第一次发送数据,并没有异常,但是server端没收到数据。第二次发送时候,才检测到连接异常。

有同学的说法是:Socket通过发送数据sendUrgentData()或PrintWriter 发送数据时的数据太小,被放到缓冲区没用实时发送导致的。后来尝试设置setSendBufferSize(1)发现能够正常出现异常,这样就能够判断实时网络连接断开了。(网上资料说sendUrgentData是实时发送数据不经过缓冲区的,但跟我实际测试的不一样,有待验证)

查看了一下源码,紧急数据的发送时间是,在之前write到OutputStream之后,在接下来write到OutputStream之前

 /**
     * Send one byte of urgent data on the socket. The byte to be sent is the lowest eight
     * bits of the data parameter. The urgent byte is
     * sent after any preceding writes to the socket OutputStream
     * and before any future writes to the OutputStream.
     * @param data The byte of data to send
     * @exception IOException if there is an error
     *  sending the data.
     * @since 1.4
     */
    public void sendUrgentData (int data) throws IOException  {
        if (!getImpl().supportsUrgentData ()) {
            throw new SocketException ("Urgent data not supported");
        }
        getImpl().sendUrgentData (data);
    }

  尝试设置setSendBufferSize(1)发现能够正常出现异常,这样就能够判断实时网络连接断开了。

fluentd的in_forward插件提供了基于udp的心跳监听,遗憾的是fluent-logger-java并没有做对应的心跳机制。

https://docs.fluentd.org/v0.12/articles/in_forward

  

  

原文地址:https://www.cnblogs.com/felixzh/p/8360927.html

时间: 2024-10-18 18:46:25

socket 如何判断远端服务器的连接状态?连接断开,需重连的相关文章

利用LoadRunner判断HTTP服务器的返回状态

利用LoadRunner判断HTTP服务器的返回状态第一种方法:是利用LR的内置函数web_get_int_property.举例:#include "web_api.h"Action(){int HttpRetCode;web_url("网易",       "URL=http://www.163.com",       "TargetFrame=_TOP",       LAST);HttpRetCode = web_ge

通过psping测试结果,初步判断远端服务器的状态

1.psping的输出结果为如下正常显示时,说明远端服务器的IP及端口可用 C:\Users\he.liming>psping 139.219.66.205:4352 PsPing v2.10 - PsPing - ping, latency, bandwidth measurement utility Copyright (C) 2012-2016 Mark Russinovich Sysinternals - www.sysinternals.com TCP connect to 139.2

一个简单的判断远端服务器端口是否通的Python脚本

import socket  #导入socket模块 sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sk.settimeout(1) try:     sk.connect(('192.168.0.1',21))    #连接21号端口,并作出判断     print 'Server port 21 OK!' except Exception:     print 'Server port 21 not connect!' sk.c

C#socket通讯客户端(连接状态监控,掉线重连)

public class SocketClientManager { public delegate void ConnectStateEventHandler(); public event ConnectStateEventHandler ConnectedEvent;//连接成功 public event ConnectStateEventHandler DisConnectedEvent;//连接失败 public delegate void ReceiveMsgEventHandler

socket.sendUrgentData判断网络远端是否断开连接

来自于 http://chenke1215.blog.163.com/blog/static/124414520103611222617/ 最近在开发中遇到一个问题,就是如何判断远端服务器是否已经断开连接,如果断开那么需要重新连接. 首先想到socket类的方法isClosed().isConnected().isInputStreamShutdown().isOutputStreamShutdown()等,但经过试验并查看相关文档,这些方法都是本地端的状态,无法判断远端是否已经断开连接. 然后

android设备判断网络连接状态

android开发中,在做网络请求前判断当前网络连接状态有时很有必要.本文将介绍如何获取android设备当前网络连接状态! 所需权限(AndroidManifest.xml文件中添加): <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> Java代码(MainActivity.java文件) package com.example.androidtest; import a

使用Python的socket模块搭建tcp服务器与客户端

# __author__ = 'ZSnail' # socket就是一个网络通讯协议 # 服务器端 import socket server = socket.socket() server.bind(('127.0.1.1', 6969)) # 绑定要监听的端口 server.listen() # 监听 print('开始等??') # 在这里会形成阻塞,一直等到有客户连接 # conn就是客户端连过来而在服务器内生成的一个连接实例 conn, address = server.accept(

Android线程中队UI进行操作、按钮长按实现连续发送命令的效果、检测socket与服务器连接状态

线程中设置UI问题: Android处于安全考虑,禁止在子线程中队系统的UI进行操作,因此,需要通过Handler对其进行处理. 在子线程中,当需要进行UI相关操作时,可通过Handler类实现. 1.在主线程中创建Handler,其功能为监听msg,当收到msg时进行一些操作 public Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) {...}}} 2

C#通过socket判断FTP服务器是否通畅并判断用户名密码是否正确

/// <summary> /// 通过socket判断ftp是否通畅 /// </summary> /// <returns></returns> public static bool CheckFtp(string ip, string ftpuser, string ftppas,out string errmsg, int port = 21) { #region 输入数据检查 if (ftpuser.Trim().Length==0) { errm