package com.scn7th.asynchronousIO;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;@Slf4jpublic class MyAsynchronousServerSocketChannel {
public static void listen() throws IOException {
AsynchronousServerSocketChannel serverSocketChannel =
AsynchronousServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8077));
Attachment attachment = new Attachment();
attachment.serverChannel = serverSocketChannel;
serverSocketChannel.accept(attachment, new ConnectionHandler());
try
{
Thread.currentThread().join();
}
catch (InterruptedException ie)
{
System.out.println("Server terminating");
}
}
private static class Attachment{
private AsynchronousServerSocketChannel serverChannel;
private AsynchronousSocketChannel clientChannel;
public boolean isReadMode;
public ByteBuffer buffer;
public SocketAddress clientAddress;
}
private static class ConnectionHandler implements CompletionHandlerAsynchronousSocketChannel, Attachment{
@Override
public void completed(AsynchronousSocketChannel
clientChannel, Attachment attachment) {
SocketAddress clientAddr = null;
try {
clientAddr = clientChannel.getRemoteAddress();
} catch (IOException e) {
e.printStackTrace();
}
log.info("Accepted connection from :{}", clientAddr);
//calls accept() on the server socket channel with
the passed Attachment object and a reference to the current
completion handler
//as arguments. This call allows the server to respond to the next
incoming connection.
attachment.serverChannel.accept(attachment, this);
Attachment newAttachment = new Attachment();
newAttachment.serverChannel = attachment.serverChannel;
newAttachment.clientChannel = clientChannel;
newAttachment.isReadMode = true;
newAttachment.clientAddress = clientAddr;
newAttachment.buffer = ByteBuffer.allocate(2048);
ReadWriteHandler readWriteHandler =
new ReadWriteHandler();
clientChannel.read(newAttachment.buffer, newAttachment, readWriteHandler);
}
@Override
public void failed(Throwable exc, Attachment attachment) {
System.out.println("Failed to connect...");
}
}
private static class ReadWriteHandler implements CompletionHandlerInteger, Attachment {
@Override
public void completed(Integer result, Attachment attachment) {
if(result == -1) {
try {
attachment.clientChannel.close();
System.out.printf("Stopped listening to client
%s%n",
attachment.clientAddress);
} catch (IOException e) {
e.printStackTrace();
}
return;
}
else {
//readMode下首先读取了数据,然后又异步向client写了原buffer。此时为readMode=false,也就是不会接收新的socket读取,除非异步完成了向client回写buffer
if(attachment.isReadMode) {
attachment.buffer.flip();
int limit = attachment.buffer.limit();
byte[] bytes = new byte[limit];
attachment.buffer.get(bytes, 0, limit);
log.info("Client at {} sends message: {}",attachment.clientAddress, new String(bytes));
attachment.isReadMode = false;
attachment.buffer.rewind();
attachment.clientChannel.write(attachment.buffer, attachment, this);
}
else {
log.info("---------write");
attachment.isReadMode = true;
attachment.buffer.clear();
attachment.clientChannel.read(attachment.buffer, attachment, this);
}
}
}
@Override
public void failed(Throwable exc, Attachment attachment) {
System.out.println("Failed to read/write...");
}
}
public static void main(String[] args) throws IOException {
listen();
}
}