我正在编写一个服务器来在客户端之间交换消息。还有一个问题需要解决,即当客户端关闭时如何释放频道。我所做的是启动一个监视所有客户端映射的监视器线程,如果在尝试write()时检测到异常,我尝试删除()一个通道。但是,关闭客户端后,监视器线程中的write()方法不会抛出异常,因此永远不会释放无用的通道。谁知道为什么?
public class ServerMonitor extends Thread{
private Map<String, SocketChannel> allClients;
private Set set;
private Iterator it;
private Entry entry;
private SocketChannel channel;
private ByteBuffer buf;
public ServerMonitor(Map<String, SocketChannel> allClients) {
this.allClients = allClients;
buf = ByteBuffer.allocateDirect(10);
byte b = 0;
buf.put(b);
buf.flip();
}
public void run(){
while(true) {
if(!allClients.isEmpty()) {
set = allClients.entrySet();
it = set.iterator();
while(it.hasNext()) {
entry = (Entry) it.next();
channel = (SocketChannel) entry.getValue();
try{
channel.write(buf);
} catch(Exception e) {
allClients.remove(entry.getKey());
//set.remove(entry);
}
}
}
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
答案 0 :(得分:1)
写入TCP套接字在本地缓冲并异步放入线路。因此,在对等关闭失败后,您不能依赖第一次写入。您可以依赖后续的写入失败,但可能需要多次写入才能实现。
答案 1 :(得分:0)
在编写通过TCP发送数据的应用程序时,我遇到了这个问题。您已经发现,了解客户端是否已关闭连接的唯一真实方法是IOException
调用write(...)
。这几乎就是它的工作方式。
有一个更清洁的解决方案。首先,您必须始终处理客户端在您不知情的情况下断开连接的情况,并在IOException
上write(...)
时正确删除它们。但是,如果客户端发送一条消息告诉服务器它正在断开连接,则可以在看到它时使用它来关闭连接。