Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java SocketChannel的write()方法在应该引发异常时不会引发异常_Java_Exception_Socketchannel - Fatal编程技术网

Java SocketChannel的write()方法在应该引发异常时不会引发异常

Java SocketChannel的write()方法在应该引发异常时不会引发异常,java,exception,socketchannel,Java,Exception,Socketchannel,我正在编写一个服务器来在客户端之间交换消息。剩下要解决的一个问题是,当客户端恰好关闭时,如何释放通道。我要做的是启动一个监视线程,在该线程中监视所有客户端映射,如果在尝试写入()时检测到异常,我将尝试删除()通道。但是,在关闭客户机之后,monitor线程中的write()方法不会引发异常,因此将永远不会释放无用的通道。有人知道为什么吗 public class ServerMonitor extends Thread{ private Map<String, SocketChannel&

我正在编写一个服务器来在客户端之间交换消息。剩下要解决的一个问题是,当客户端恰好关闭时,如何释放通道。我要做的是启动一个监视线程,在该线程中监视所有客户端映射,如果在尝试写入()时检测到异常,我将尝试删除()通道。但是,在关闭客户机之后,monitor线程中的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();
        }
    }
}
公共类ServerMonitor扩展线程{
私人客户;
私有集;
私有迭代器;
私人入境;
专用信道;
私人ByteBuffer buf;
公共服务器监视器(映射所有客户端){
this.allClients=allClients;
buf=字节缓冲区分配目录(10);
字节b=0;
buf.put(b);
buf.flip();
}
公开募捐{
while(true){
如果(!allClients.isEmpty()){
set=allClients.entrySet();
it=set.iterator();
while(it.hasNext()){
entry=(entry)it.next();
channel=(SocketChannel)entry.getValue();
试一试{
通道写入(buf);
}捕获(例外e){
allClients.remove(entry.getKey());
//设置。删除(条目);
}
}
}
试一试{
线程。睡眠(1000*5);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}

}

对TCP套接字的写入在本地进行缓冲,并异步连接。因此,您不能依赖对等方关闭后的第一次写入失败。您可以依赖于随后的写入失败,但可能需要多次写入才能达到目的。

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


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

this.allClients=allClients
@fge我确实想执行此操作。allClients=allClients;因为当监视器线程检测到无法写入字节的通道时,我需要修改源AllClient(释放一个无用的通道)。所以我可以将bytebuffer.size()字节写入通道,以便在第一次写入时检测异常吗?我刚刚回答了这个问题。不。ByteBuffer.size()与此无关。大小取决于TCP本身吗?你说的是什么大小?你说我不能依靠第一次写入()来处理IOEXECTION,因为字节会写入缓冲区,但不会立即写入客户端。所以我猜缓冲区中可能有一个大小,当缓冲区有“大小”字节时,字节就会被传递。是的,我真的按照你说的做了,但是调用write(…)不会导致IOException,这让我很困惑。就像EJP所说的,你不能依赖于某个特定的写失败,但它最终会失败。向套接字写入的数据越多,它失败的速度就越快。