XNIO:如何在关闭连接时收到通知?

时间:2015-07-02 23:47:13

标签: java nio

我正在尝试使用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 socket = new Socket();
socket.connect(server.getLocalAddress());

然后断开连接

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();

问题仍然存在:我怎样才能知道对等体何时完全断开连接而只关闭仅写入?

1 个答案:

答案 0 :(得分:0)

尝试将您的侦听器附加到下游频道:

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();

&#39;关闭&#39;附加到StreamConnection的监听器只有在SourceChannel(下游信道)和&amp; SinkChannel(上游频道)已关闭。

编辑:(完整示例)

服务器:

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();

客户端:

try(Socket client = new Socket(Server.SERVER_HOST,Server.SERVER_PORT);
        PrintWriter echoWriter = new PrintWriter(client.getOutputStream(),true);)
    {
        echoWriter.println("Hello");
        Thread.sleep(1000);
        client.close();
        //your Server Source Channel close listener will notify you from here
        Thread.sleep(1000);
    }catch(Exception e){
        e.printStackTrace();
    }