java socket 自动重连_socket 如何判断远端服务器的连接状态?连接断开,需重连...
fluent-logger-java?is a Java library, to record events via Fluentd, from Java application.?https://github.com/fluent/fluent-logger-java
使用該sdk過程發(fā)現(xiàn),tcp連接斷開之后,該sdk的重連機(jī)制無效。
2018-01-26 12:36:25,620 ERROR [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 遠(yuǎn)程端連接如果關(guān)閉的話,就要重建連接。Socket的類提供了一些已經(jīng)封裝好的方法, 如 ?isClosed()、isConnected()、isInputStreamShutdown()、isOutputStreamShutdown()等,
在測試時發(fā)現(xiàn),這些方法都是本地端的狀態(tài),無法判斷遠(yuǎn)端是否已經(jīng)斷開連接。
有些同學(xué)處理類似問題時,通過OutputStream發(fā)送一段測試數(shù)據(jù),如果發(fā)送失敗就表示遠(yuǎn)端已經(jīng)斷開連接,類似ping,但是這樣會影響到正常的輸出數(shù)據(jù),遠(yuǎn)端無法把正常數(shù)據(jù)和測試數(shù)據(jù)分開。
其實(shí),這種方法也是可以的,只不過,不要發(fā)送測試數(shù)據(jù),直接發(fā)送需要發(fā)送的數(shù)據(jù),一旦失敗,就主動close socket,再新建連接,再重新發(fā)送就行了。
也有些同學(xué)想到通過發(fā)送緊急數(shù)據(jù),來驗證連接狀態(tài),見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);
}
可通過如下寫法實(shí)現(xiàn):
/**
* 判斷是否斷開連接,斷開返回true,沒有返回false
* @param socket
* @return
*/
public Boolean isServerClose(Socket socket){
try{
socket.sendUrgentData(0xFF);//發(fā)送1個字節(jié)的緊急數(shù)據(jù),默認(rèn)情況下,服務(wù)器端沒有開啟緊急數(shù)據(jù)處理,不影響正常通信
return false;
}catch(Exception se){
return true;
}
}
前提:對方Socket的SO_OOBINLINE屬性沒有打開,就會自動舍棄這個字節(jié),而SO_OOBINLINE屬性默認(rèn)情況下就是關(guān)閉的
見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;
當(dāng)然,我覺得也可以通過定時發(fā)送緊急數(shù)據(jù)來做心跳,確保tcp長連接保活,對方可以不用回應(yīng)。
測試結(jié)果:
這兩種方式再連接斷開后的第一次發(fā)送數(shù)據(jù),并沒有異常,但是server端沒收到數(shù)據(jù)。第二次發(fā)送時候,才檢測到連接異常。
有同學(xué)的說法是:Socket通過發(fā)送數(shù)據(jù)sendUrgentData()或PrintWriter 發(fā)送數(shù)據(jù)時的數(shù)據(jù)太小,被放到緩沖區(qū)沒用實(shí)時發(fā)送導(dǎo)致的。后來嘗試設(shè)置setSendBufferSize(1)發(fā)現(xiàn)能夠正常出現(xiàn)異常,這樣就能夠判斷實(shí)時網(wǎng)絡(luò)連接斷開了。(網(wǎng)上資料說sendUrgentData是實(shí)時發(fā)送數(shù)據(jù)不經(jīng)過緩沖區(qū)的,但跟我實(shí)際測試的不一樣,有待驗證)
查看了一下源碼,緊急數(shù)據(jù)的發(fā)送時間是,在之前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);
}
嘗試設(shè)置setSendBufferSize(1)發(fā)現(xiàn)能夠正常出現(xiàn)異常,這樣就能夠判斷實(shí)時網(wǎng)絡(luò)連接斷開了。
fluentd的in_forward插件提供了基于udp的心跳監(jiān)聽,遺憾的是fluent-logger-java并沒有做對應(yīng)的心跳機(jī)制。
https://docs.fluentd.org/v0.12/articles/in_forward
總結(jié)
以上是生活随笔為你收集整理的java socket 自动重连_socket 如何判断远端服务器的连接状态?连接断开,需重连...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大脑镰钙化是什么意思
- 下一篇: gitblit mysql_CentOS