首先定義服務端
先定義服務端的關閉,這個在多處函數中用得着:只要是實現了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);
}
}