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