检查ClientSocket是否在java中断开连接 [英] Checking if a ClientSocket has disconnected in java hangs

查看:702
本文介绍了检查ClientSocket是否在java中断开连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个跟进:

这个问题

基本上,我有一个服务器循环,用于管理与一个单独客户端的连接。在循环中的某一点,如果ClientSocket存在,它会尝试读取以检查客户端是否仍然连接:

Basically, I have a server loop that manages a connection to one solitary client. At one point in the loop, if a ClientSocket exists it attempts a read to check if the client is still connected:

if (bufferedReader.read()==-1 ) {
       logger.info("CONNECTION TERMINATED!");
       clientSocket.close(); 
       setUpSocket(); //sets up the server to reconnect to the client
}else{
        sendHeartBeat(); //Send a heartbeat to the client
}

问题是,一旦一个套接字已创建应用程序将挂起读取,我假设等待永远不会来的数据,因为客户端永远不会发送到服务器。在此之前没问题,因为这个正确处理断开连接(当客户端断开连接时读取最终会失败)并且循环将尝试重新建立连接。但是,我现在已经添加了上面的sendHeartBeat()方法,它定期让客户端知道服务器仍在运行。如果读取持有线程,则心跳不会发生!

The problem is, that once a socket has been created the application will hang on the read, I assume waiting for data that will never come, since the client never sends to the server. Before this was OK, because this correctly handled disconnects (the read would eventually fail when the client disconnected) and the loop would attempt reestablish the connection. However, I now have added the above sendHeartBeat() method, which periodically lets the client know the server is still up. If the read is holding the thread then the heartbeats never happen!

所以,我假设我正在测试连接是否仍然不正确。我可以,作为一个快速的黑客,在一个单独的线程中运行bufferedReader.read(),但随后我会遇到各种各样的并发问题,我真的不想处理。

So, I assume I am testing if the connection is still up incorrectly. I could, as a quick hack, run the bufferedReader.read() in a seperate thread, but then I'll have all sorts of concurrency issues that I really don't want to deal with.

所以问题是几折:
1)我是否正确检查客户端断开连接?
2)如果没有,我该怎么做?
3)如果我正确地做了我的工作方式,那么我的阅读不会让流程成为人质?或者是穿线唯一的方式?

So the question is a few fold: 1) Am I checking for a client disconnect correctly? 2) If not, how should I do it? 3) If I am doing it correctly how I do I get the read to not hold the process hostage? Or is threading the only way?

推荐答案

创建套接字时,首先设置超时:

When you create your socket, first set a timeout:

private int timeout    = 10000;
private int maxTimeout = 25000;

clientSocket.setSoTimeout(timeout);

有了这个,如果读取超时,你将得到 java.net .SocketTimeoutException (你必须抓住)。因此,您可以执行类似这样的操作,假设您之前已设置SO_TIMEOUT,如上所示,并假设心跳将始终从远程系统获得响应:

With this, if a read times out you'll get java.net.SocketTimeoutException (which you have to catch). Thus, you could do something like this, assuming you've previously set the SO_TIMEOUT as shown above, and assuming that the heartbeat will always get a response from the remote system:

volatile long lastReadTime;

try {
    bufferedReader.read();
    lastReadTime = System.currentTimeMillis();
} catch (SocketTimeoutException e) {
    if (!isConnectionAlive()) {
        logger.info("CONNECTION TERMINATED!");
        clientSocket.close(); 
        setUpSocket(); //sets up the server to reconnect to the client
    } else {
        sendHeartBeat(); //Send a heartbeat to the client
    }
}

public boolean isConnectionAlive() {
    return System.currentTimeMillis() - lastReadTime < maxTimeout;
}

处理此问题的常用方法是将超时设置为某个数字(例如10秒),然后跟踪上次成功读取套接字的时间。如果已超过2.5倍的超时,则放弃客户端并关闭套接字(因此发送FIN数据包到另一方,以防万一)。

A common way of handling this is setting the timeout to some number (say 10 seconds) and then keeping track of the last time you successfully read from the socket. If 2.5 times your timeout have elapsed, then give up on the client and close the socket (thus sending a FIN packet to the other side, just in case).

如果心跳从远程系统获得任何响应,但只是在连接断开时最终生成IOException的一种方式,然后你可以这样做(假设sendHeartBeat本身不会抛出IOException):

If the heartbeat will not get any response from the remote system, but is just a way of ultimately generating an IOException earlier when the connection has fallen down, then you could do this (assuming that the sendHeartBeat itself will not throw an IOException):

try {
    if (bufferedReader.read() == -1) {
        logger.info("CONNECTION TERMINATED with EOF!");
        resetConnection();
    }
} catch (SocketTimeoutException e) {
    // This just means our read timed out ... the socket is still good
    sendHeartBeat(); //Send a heartbeat to the client
} catch (IOException e) {
    logger.info("CONNECTION TERMINATED with Exception " + e.getMessage());
    resetConnection();
}

....

private void resetConnection() {
    clientSocket.close(); 
    setUpSocket(); //sets up the server to reconnect to the client
}

这篇关于检查ClientSocket是否在java中断开连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆