我正在构建一个IM应用程序,从客户端,我编写这样的代码(我在阻塞模式下使用SocketChannel,历史原因,我认为它与此问题无关):
try {
LogUtil.info(TAG, this.label + " tryConnect, attempt = " + (3 - retry));
clientChannel = SocketChannel.open();
clientChannel.configureBlocking(true);
clientChannel.socket().setSoTimeout(100);
clientChannel.socket().setTrafficClass(0x10);
clientChannel.socket().setTcpNoDelay(true);
clientChannel.socket().setPerformancePreferences(3, 3, 1);
clientChannel.socket().connect(address, 10000);
LogUtil.info(TAG, this.label + " socket connected successfully");
break;
} catch (AlreadyConnectedException ace) {
LogUtil.info(TAG, label + " AlreadyConnectedException");
break;
} catch (NotYetConnectedException ace) {
LogUtil.info(TAG, label + " NotYetConnectedException");
break;
} catch (SocketTimeoutException e) {
LogUtil.info(TAG, label + " SocketTimeoutException");
break;
} catch (Exception e) {
clientChannel = null;
throw new SocketConnectionException(label + ", exception = " + ThrowableUtil.stackTraceToString(e));
}
问题是,当我有时关闭服务器时,客户端将继续成功写入(小块数据,总共少于50个字节)。大约3分钟后,客户端会遇到写入失败异常。
服务器关闭后,为什么客户端没有立即失败?我该如何解决这个问题?也许将发送缓冲区减少到10个字节?
这是我实际写数据的方式:
public void writeXML(ByteBuffer buffer, int retry) {
synchronized (writeLock) {
if (retry < 0) {
throw new SocketConnectionException(label + "Write Exception");
}
tryConnect(false);
try {
int written = 0;
while (buffer.hasRemaining()) {
// I think it should be an exception here after I closed server
written += clientChannel.write(buffer);
}
if (LogUtil.debug) {
LogUtil.info(TAG, "\t successfully written = " + written);
}
} catch (Exception e) {
e.printStackTrace();
tryConnect(true);
writeXML(buffer, --retry);
}
}
}
答案 0 :(得分:0)
因为您和对等应用程序之间存在:
通常在写入时,数据会被传输到套接字发送缓冲区,并在线路上异步发送。因此,如果发送它会发生错误,您将无法立即发现。您将只知道TCP发送的时间是否足够,无论TCP的内部发送超时时间段是什么,以确定存在错误情况。 之后的下一次写入(或读取)将获得错误。可能只有几分钟的路程。
答案 1 :(得分:-1)
事实证明,read
操作可以立即检测到已关闭的连接(通过@ EJP的回复,它与丢失的连接不同)。
在我的阅读主题中,我有这句话:
int read = clientChannel.read(buffer);
,当它返回-1
表示服务器关闭(故意关机不同于网络不可达),我想write
操作需要填充TCP发送缓冲区,所以没办法检测连接快速丢失。