SocketChannel的write()方法在应该执行时不会抛出异常

时间:2013-06-21 13:03:25

标签: java exception socketchannel

我正在编写一个服务器来在客户端之间交换消息。还有一个问题需要解决,即当客户端关闭时如何释放频道。我所做的是启动一个监视所有客户端映射的监视器线程,如果在尝试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();
        }
    }
}

}

2 个答案:

答案 0 :(得分:1)

写入TCP套接字在本地缓冲并异步放入线路。因此,在对等关闭失败后,您不能依赖第一次写入。您可以依赖后续的写入失败,但可能需要多次写入才能实现。

答案 1 :(得分:0)

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

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