Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/317.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.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 XNIO:如何在连接关闭时获得通知?_Java_Nio - Fatal编程技术网

Java XNIO:如何在连接关闭时获得通知?

Java XNIO:如何在连接关闭时获得通知?,java,nio,Java,Nio,我正在尝试使用XNIO编写一个服务器。我希望在客户端关闭与服务器的连接时收到通知 XnioWorker worker = Xnio.getInstance().createWorker(OptionMap.EMPTY); AcceptingChannel<StreamConnection> server = worker.createStreamConnectionServer( new InetSocketAddress(0), acceptingChannel

我正在尝试使用XNIO编写一个服务器。我希望在客户端关闭与服务器的连接时收到通知

XnioWorker worker = Xnio.getInstance().createWorker(OptionMap.EMPTY);

AcceptingChannel<StreamConnection> server = worker.createStreamConnectionServer(
        new InetSocketAddress(0), acceptingChannel -> {
            try {
                StreamConnection connection = acceptingChannel.accept();
                if (connection != null) {
                    System.out.println("accepted");

                    connection.setCloseListener(channel -> System.out.println("closed"));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }, OptionMap.EMPTY);
server.resumeAccepts();
然后断开连接

socket.close();
System.out.println("client connection closed");
我只能在控制台中看到以下几行

accepted
client connection closed
但是亲密的听众没有发出任何信息。有没有办法得到这样的通知

更新

好的,我可以学习当同级关闭时。然后我可以关闭源通道:

ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel();
sourceChannel.setReadListener(channel -> {
    try {
        int byteNum = channel.read(buffer);
        if (byteNum == -1) channel.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
});
sourceChannel.resumeReads();
但水槽频道怎么办?换句话说,我如何区分对等方是否完全关闭了连接

socket.close();
还是半关

socket.getOutputStream().close();
更新2

读取时不需要显式关闭源通道。XNIO自己做这件事

ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel();
sourceChannel.setReadListener(channel -> {
    try {
        channel.read(buffer);
    } catch (IOException e) {
        e.printStackTrace();
    }
});
sourceChannel.resumeReads();

问题仍然存在:如何知道对等方何时完全断开连接而不是仅关闭写入?

尝试将侦听器连接到下游通道:

connection.getSourceChannel()
    .setCloseListener((ch)->System.out.println("client connection closed"));

//At some level you need to make sure your source channel is enabling reads.
connection.getSourceChannel().resumeReads();
仅当SourceChannel(下游通道)和SinkChannel(上游通道)都关闭时,才会调用连接到流连接的“close”侦听器

编辑:(完整示例)

服务器:

XnioWorker worker = Xnio.getInstance().createWorker(OptionMap.EMPTY);

AcceptingChannel<StreamConnection> server = worker.createStreamConnectionServer(
    new InetSocketAddress(0), acceptingChannel -> {
        try {
            StreamConnection connection = acceptingChannel.accept();
            if (connection != null) {
                System.out.println("accepted");

                connection.setCloseListener(channel -> System.out.println("closed"));
            }
            ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel();
            ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel();

            sourceChannel
                        .setCloseListener((t)->System.out.println("Source Closed"));
            sinkChannel
                        .setCloseListener((t)->System.out.println("Sink Closed"));

            sourceChannel.setReadListener((channel)->{
                    try{
                        ByteBuffer bb = ByteBuffer.allocate(15);
                        StringBuilder builder = new StringBuilder();
                        while(sourceChannel.read(bb) > 0){
                            bb.flip();
                            while(bb.position() < bb.limit()){
                                builder.append((char)bb.get());
                            }
                            bb.clear();
                        }
                        System.out.println(builder.toString());
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                });

            sourceChannel.resumeReads();
            sinkChannel.resumeWrites();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }, OptionMap.EMPTY);

server.resumeAccepts();

请尝试将侦听器连接到下游频道:

connection.getSourceChannel()
    .setCloseListener((ch)->System.out.println("client connection closed"));

//At some level you need to make sure your source channel is enabling reads.
connection.getSourceChannel().resumeReads();
仅当SourceChannel(下游通道)和SinkChannel(上游通道)都关闭时,才会调用连接到流连接的“close”侦听器

编辑:(完整示例)

服务器:

XnioWorker worker = Xnio.getInstance().createWorker(OptionMap.EMPTY);

AcceptingChannel<StreamConnection> server = worker.createStreamConnectionServer(
    new InetSocketAddress(0), acceptingChannel -> {
        try {
            StreamConnection connection = acceptingChannel.accept();
            if (connection != null) {
                System.out.println("accepted");

                connection.setCloseListener(channel -> System.out.println("closed"));
            }
            ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel();
            ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel();

            sourceChannel
                        .setCloseListener((t)->System.out.println("Source Closed"));
            sinkChannel
                        .setCloseListener((t)->System.out.println("Sink Closed"));

            sourceChannel.setReadListener((channel)->{
                    try{
                        ByteBuffer bb = ByteBuffer.allocate(15);
                        StringBuilder builder = new StringBuilder();
                        while(sourceChannel.read(bb) > 0){
                            bb.flip();
                            while(bb.position() < bb.limit()){
                                builder.append((char)bb.get());
                            }
                            bb.clear();
                        }
                        System.out.println(builder.toString());
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                });

            sourceChannel.resumeReads();
            sinkChannel.resumeWrites();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }, OptionMap.EMPTY);

server.resumeAccepts();

通常,您必须从连接中读取,才能从对等方查看FIN。在大多数套接字API中没有其他方法,在任何API中都没有其他方法。在底部,Berkeley Sockets API级别,检测流结束的唯一机制是读取。在大多数套接字API中没有其他方法,在任何API中都没有其他方法。在底部,Berkeley Sockets API级别,检测流结束的唯一机制是读取。在初始问题的范围内(更新之前),它确实有效,不是吗?不,它没有。如果我不手动关闭频道,则不会调用侦听器。我已更新了答案以说明我的示例,此示例是否适用于您?是的,现在源频道已关闭。但是接收器通道和连接保持打开状态。StreamConnection和源/接收器通道是xnio级别的抽象。在TCP协议中,没有这样的通知(比如我仍然在“监听”,但不会再“告诉”你任何事情),所以我担心你试图实现的是行不通的。然而,我觉得奇怪的是,为什么在客户端关闭InputStream或OutputStream最终会导致由SourceStream触发的关闭事件。在初始问题的范围内(更新之前),它确实有效,不是吗?不,它没有。如果我不手动关闭频道,则不会调用侦听器。我已更新了答案以说明我的示例,此示例是否适用于您?是的,现在源频道已关闭。但是接收器通道和连接保持打开状态。StreamConnection和源/接收器通道是xnio级别的抽象。在TCP协议中,没有这样的通知(比如我仍然在“监听”,但不会再“告诉”你任何事情),所以我担心你试图实现的是行不通的。然而,我觉得奇怪的是,为什么在客户端级别关闭InputStream或OutputStream最终会导致由SourceStream触发的关闭事件。