我正在构建一个即时通信应用,在客户端,我的代码是这样写的(我在阻塞模式下使用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);
}
}
}发布于 2017-06-29 13:48:32
因为在您和对等应用程序之间有:
套接字发送缓冲区TCP implementation
通常情况下,当你写的时候,数据只是被传输到你的套接字发送缓冲区中,并在网络上异步发送。因此,如果发送它时出现错误,您不会立即发现。只有当TCP发送失败的次数超过TCP的内部发送超时时间,您才能确定是否存在错误条件。之后的下一次写(或读)将得到错误。可能需要几分钟的时间。
发布于 2017-06-29 17:51:52
事实证明,read操作可以立即检测到关闭的连接(通过@EJP的回复,这与丢失的连接不同)。
在我的阅读线程中,我有这样一句话:
int read = clientChannel.read(buffer);,当它返回-1表示服务器已关机(故意关机与网络不可达不同)时,我猜write操作需要填充TCP send buffer,因此没有办法快速检测连接丢失。
https://stackoverflow.com/questions/44816787
复制相似问题