0

我正在编写一个服务器来在客户端之间交换消息。一个有待解决的问题是如何在客户端关闭时释放通道。我所做的是启动一个监控线程,在该线程中监控所有客户端映射,如果在尝试对其进行 write() 时检测到异常,我会尝试 remove() 一个通道。但是,在关闭客户端后,监控线程中的 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();
        }
    }
}

}

4

2 回答 2

1

对 TCP 套接字的写入在本地缓冲并异步连接到网络上。所以你不能依赖对等体关闭后的第一次写入失败。您可以依靠随后的写入失败,但可能需要多次写入才能到达那里。

于 2013-06-21T13:25:06.810 回答
0

我在编写通过 TCP 发送数据的应用程序时遇到了这个问题。您已经发现了解客户端是否关闭连接的唯一真正方法是IOException调用write(...). 这几乎就是它的工作方式。

有一个更清洁的解决方案。首先,您必须始终处理客户端在您不知情的情况下断开连接的情况,并在您打开时正确删除IOException它们write(...)。但是,如果客户端发送一条消息告诉服务器它正在断开连接,您可以在看到它时使用它来关闭连接。

于 2013-06-21T13:47:01.907 回答