我正在尝试使用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();
问题仍然存在:我怎样才能知道对等体何时完全断开连接而只关闭仅写入?
答案 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();
}