首先定义服务端
先定义服务端的关闭,这个在多处函数中用得着:只要是实现了closeable接口的都可以调用
private void close(Closeable closeable) throws IOException {
if(closeable != null){
closeable.close();
}
}
然后是我们用到的主要的函数:
public void start() throws IOException {
try {
serverSocketChannel = AsynchronousServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(hosts,port));
System.out.println("start server");
while (true) {
serverSocketChannel.accept(null,new AcceptHandler()); // 1
System.in.read();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
close(serverSocketChannel);
}
}
这里我们只解释while循环里面:这里等待客户端的连接,第一个参数是个attachment,也就是附件,需要传入到后面的AcceptHandler()
处理的参数,这里为空。这里的异步调用,返回的结果交给Accepthandler处理,为了防止频繁调用,影响性能,这里用read,进行手动阻塞。
接下来是AcceptHandler()的定义
private class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel,Object>{
@Override
public void completed(AsynchronousSocketChannel result, Object attachment) {
if(serverSocketChannel.isOpen()){
serverSocketChannel.accept(null,this); // 0
}
AsynchronousSocketChannel clientChannel = result; // 1
if(clientChannel != null && clientChannel.isOpen()){
ClientHandler handler = new ClientHandler(clientChannel); // 2
ByteBuffer buffer = ByteBuffer.allocate(1024);
Map<String, Object> info = new HashMap<>();
info.put("type","read");
info.put("buffer",buffer);
clientChannel.read(buffer,info,handler); // 3
}
}
@Override
public void failed(Throwable exc, Object attachment) {
System.out.println("error");
}
}
这里需要实现CompletionHandler
接口,接口有两个方法,我们只实现调用成功的方法。
这里的result
是前面accept调用成功返回的结果,后面的attachment是我们传入的附件,我们上一步传入的附件为空。
【0】我们继续让accept继续监听,附件依旧为空,处理类还是设置为这个,这里用this指代。
【2】我们定义一个类用于客户端异步的响应处理.
【3】客户端把内容读到buffer里面,把Map作为attachment,用于handler响应处理
下面是相应的handler处理类:
public class ClientHandler implements CompletionHandler<Integer, Object> {
private AsynchronousSocketChannel clientChannel;
public ClientHandler(AsynchronousSocketChannel clientChannel) {
this.clientChannel = clientChannel;
}
@Override
public void completed(Integer result, Object attachment) { // 0
Map<String,Object> info = (Map<String, Object>) attachment;
String type = (String) info.get("type");
if("read".equals(type)){
ByteBuffer buffer = (ByteBuffer) info.get("buffer");
buffer.flip();
info.put("type","write");
clientChannel.write(buffer,info,this);
buffer.clear();
}else if("write".equals(type)){
ByteBuffer buffer = ByteBuffer.allocate(1024);
info = new HashMap<>();
info.put("type","read");
info.put("buffer",buffer);
clientChannel.read(buffer,info,this);
}
}
@Override
public void failed(Throwable exc, Object attachment) {
}
}
这里和上面的差不多,read函数返回的是一个Integer,attachment传入的是一个map,我们可以根据map得到请求处理的类型,不同的类型,我们分别进行相应的处理。
下面是客户端
public void start() throws IOException {
try {
SocketChannel = AsynchronousSocketChannel.open();
Future<Void> future = SocketChannel.connect(new InetSocketAddress(hosts,port));
future.get();
BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
while(true){
String input = consoleReader.readLine();
byte [] inputbyte = input.getBytes();
ByteBuffer buffer = ByteBuffer.wrap(inputbyte);
Future<Integer> writeResult = SocketChannel.write(buffer);
writeResult.get();
buffer.flip();
Future<Integer> readResult = SocketChannel.read(buffer);
readResult.get();
String echo = new String(buffer.array());
buffer.clear();
System.out.println(echo);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}finally {
close(SocketChannel);
}
}