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

  

  

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

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

    利用LoadRunner判断HTTP服务器的返回状态第一种方法:是利用LR的内置函数web_get_int_property.举例:#include "web_api.h"Acti ...

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

    1.psping的输出结果为如下正常显示时,说明远端服务器的IP及端口可用 C:\Users\he.liming>psping 139.219.66.205:4352 PsPing v2.10 ...

  3. 怎样实时判断socket连接状态?

    对端正常close socket,或者进程退出(正常退出或崩溃),对端系统正常关闭 这种情况下,协议栈会走正常的关闭状态转移,使用epoll的话,一般要判断如下几个情况 处理可读事件时,在循环read ...

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

    private static ManualResetEvent timeoutObject; private static Socket socket = null; private static b ...

  5. 系统编程-网络-tcp客户端服务器编程模型(续)、连接断开、获取连接状态场景

    相关博文: 系统编程-网络-tcp客户端服务器编程模型.socket.htons.inet_ntop等各API详解.使用telnet测试基本服务器功能 接着该上篇博文,咱们继续,首先,为了内容的完整性 ...

  6. loadrunner:判断是否服务器连接池瓶颈

    分析Web Resources中的Connections per second可以判断是否服务器连接池瓶颈. connections per second会给出两种不同状态的连接数:中断的连接和新建的 ...

  7. Linux中通过Socket文件描述符寻找连接状态介绍

    针对下文的总结:socket是一种文件描述符 进程的打开文件描述符表 Linux的三个系统调用:open,socket,pipe 返回的都是一个描述符.不同的进程中,他们返回的描述符可以相同.那么,在 ...

  8. [转]Linux服务器上11种网络连接状态 和 TCP三次握手/四次挥手详解

    一.Linux服务器上11种网络连接状态: 图:TCP的状态机 通常情况下:一个正常的TCP连接,都会有三个阶段:1.TCP三次握手;2.数据传送;3.TCP四次挥手. 注:以下说明最好能结合”图:T ...

  9. rtmp一些状态信息详解-as连接FMS服务器报错状态汇总~~

    原地址:http://help.adobe.com/zh_CN/AIR/1.5/jslr/flash/events/NetStatusEvent.html 下表说明了 code 和 level 属性可 ...

随机推荐

  1. [转]web串口调试助手,浏览器控制串口设备

    本文转自:https://blog.csdn.net/ldevs/article/details/39664697 打开串口时查找可用串口供选择 通过javascript调用activex控制串口收发 ...

  2. [转]windows BLE编程 net winform 连接蓝牙4.0

    本文转自:https://www.cnblogs.com/webtojs/p/9675956.html winform 程序调用Windows.Devices.Bluetoot API 实现windo ...

  3. C#通过虚方法实现方法重写—多态。

    class Program { //希望person存的是哪个类的对象就调用哪个类的方法 //第一步 将父类中对应方法家virtual关键字 变为虚方法(子类可重写) //子类中方法用override ...

  4. 【Linux命令】grep命令

    1.作用 Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expression Print,表示全 ...

  5. 【Tomcat】上线部署tomcat。常用命令

    ps -ef | grep tomcat-web [查询tomact进程]kill -9 pid [结束tomcat进程]/opt/tomcat-web/bin/startup.sh [启动tomca ...

  6. Hibernate入门(七)一对多入门案例

    一对多 场景模拟:用户(一)对订单(多) 1.建表 创建客户表,字段有:客户id,客户姓名,客户性别,客户年龄,客户年纪,客户电话. 创建订单表,字段有:订单编号,明细编号,客户编号(外键) DROP ...

  7. linux 中rc是什么意思

    在Linux中,最为常用的缩略语也许是"rc" 它是"runcomm"的缩写――即名词"run command"(运行命令)的简写.rc&q ...

  8. Less 结合 nth-child 选择器循环生成样式

    问题描述: 实现头像的堆叠效果 从第二个头像开始,每个头像都会盖住前一个头像上,遮盖的宽度为 30px 实现叠加的方式有很多,比如给每个头像添加 translateX 属性,或者使用负值 margin ...

  9. 获取邮箱的DNS和MX 工具类

    1.导入Maven  DNS  包: <dependency> <groupId>dnsjava</groupId> <artifactId>dnsja ...

  10. vue从入门到进阶:指令与事件(二)

    一.插值 v-once 通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新.但请留心这会影响到该节点上所有的数据绑定: span v-once>这个将不会改 ...