摘要:一概述在引入同步非阻塞包之后,終于在版本加入了異步的。注意,無論用還是,這里的調用都是非阻塞的立即返回。不過,由于朝鮮還沒有研發出能夠重返大氣層的運載火箭,所以大浦洞號尚不具備搭載彈頭的攻擊能力。
一、概述
JDK在1.4引入NIO(同步非阻塞)包之后,終于在1.7版本加入了異步IO的AIO。
同步異步阻塞和非阻塞等概念,建議參考 《Unix網絡編程》 卷1. ,這里只談AIO的api。
AsynchronousSocketChannel
AsynchronousServerSocketChannel
AsynchronousFileChannel
AsynchronousDatagramChannel
三、通過aio實現server先看下AsynchronousServerSocketChannel,它有兩個構造方法,選擇哪個構造方法,也就選擇了不同的編程模型,分別是Future機制和Handler回調機制。Future機制適合需要同步等待獲取結果的,Handler機制則看上去則更像純異步。當然,結果都是一樣的,看自己需要或者喜歡哪個模型吧。
public abstract Futureaccept(); public abstract void accept(A attachment, CompletionHandler handler);
先看看AsynchronousServerSocketChannel來啟動一個server,代碼如下。注意accept,無論用future還是handler,這里的調用都是非阻塞的立即返回。這里選用handler的方式,如果有客戶端連接上來,handler的會被回調。
public class AioServer { public final int port = 8080; public final int backlog = 2; //跟bio和nio的backlog其實是一樣的。指定accpet等待隊列的長度 private AioAcceptHandler acceptHandler; private AsynchronousServerSocketChannel serverSocket; public static void main(String[] args) throws Exception { new AioServer().startup(); } private void startup() throws Exception { int availableProcessors = Runtime.getRuntime().availableProcessors(); ExecutorService channelWorkers = Executors.newFixedThreadPool(availableProcessors * 2); AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withCachedThreadPool(channelWorkers , 1); serverSocket = AsynchronousServerSocketChannel.open(channelGroup); serverSocket.bind(new InetSocketAddress(port), backlog); acceptHandler = new AioAcceptHandler(); accept(); } public void accept() { serverSocket.accept(this, acceptHandler); //非阻塞 } }
接下來CompletionHandler的接口吧,代碼如下。看到泛型的 V result 就說嘛,當我們使用CompletionHandler的時候,自己需要清楚的知道返回結果是什么。
比如accept中指定的CompletionHandler。它是處理接受連接的,成功返回的話,結果就是套接字,那么我們就要指定泛型V的實際類型為AsynchronousSocketChannel。
再比如read方法中指定CompletionHandler。read是將數據讀取到ByteBuffer,而回調CompletionHandler的時候,結果V是讀取的數量。所以我們就要指定泛型V的實際類型為Integer。
具體可以看下面的實現代碼 AioAcceptHandler 和 AioReadHandler。
public interface CompletionHandler{ //調用結果,附件 void completed(V result, A attachment); //異常對象、附件 void failed(Throwable exc, A attachment); }
AioAcceptHandler
public class AioAcceptHandler implements CompletionHandler{ public void completed(AsynchronousSocketChannel socket, AioServer aioServer) { try { System.out.printf("客戶端%s連接成功. ", socket.getRemoteAddress().toString()); readData(socket); } catch (Exception e) { e.printStackTrace(); try { socket.close(); } catch (IOException e1) {} } finally { aioServer.accept(); } } private void readData(AsynchronousSocketChannel socket) { ByteBuffer buf = ByteBuffer.allocate(32); //測試時,可以不設置太大,觀察aio的多次read socket.read(buf, buf, new AioReadHandler(socket)); } public void failed(Throwable exc, AioServer aioServer) { exc.printStackTrace(); } }
AioReadHandler
public class AioReadHandler implements CompletionHandler{ private AsynchronousSocketChannel socket; private ByteArrayOutputStream baos = new ByteArrayOutputStream(); public AioReadHandler(AsynchronousSocketChannel socket){ this.socket = socket; } public void completed(Integer result, ByteBuffer buf) { System.out.println("result = " + result + " buf = " + buf); if (result > 0) { buf.flip(); try { baos.write(buf.array()); } catch (IOException e) { e.printStackTrace(); } buf.clear(); socket.read(buf, buf, this); } else if (result == -1) { //result為-1的時候,客戶端的socket已經正常關閉。 try { System.out.printf("客戶端%s已經斷開. ", socket.getRemoteAddress().toString()); String info = new String(baos.toByteArray(), Charset.forName("UTF8")); System.out.println(info); } catch (Exception e) { e.printStackTrace(); } finally { buf = null; try { socket.close(); } catch (IOException e) {} } } } public void failed(Throwable exc, ByteBuffer buf) { exc.printStackTrace(); } }
基本上,一個簡單的AIOServer就上面這點代碼拉。實際上我感覺代碼比NIO用Selector的方式還是簡單清晰多了。至于aio的原理,實際上就是去看看epoll等資料就知道了。
這里附上一個測試的客戶端代碼:
public class BioClient { public static void main(String[] args) throws Exception { String txt = "美國在發布的朝鮮軍力評估報告中也認為:“朝鮮發展航天運載工具對開發射程可達美國的遠程導彈意義重要,射程也許能覆蓋美國部分地區。不過,由于朝鮮還沒有研發出能夠重返大氣層的運載火箭,所以‘大浦洞2號’尚不具備搭載彈頭的攻擊能力。”"; Socket socket = new Socket("localhost", 8080); PrintStream print = new PrintStream(socket.getOutputStream()); print.print(txt); print.close(); socket.close(); System.out.println("ok."); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/65706.html
摘要:后改良為用線程池的方式代替新增線程,被稱為偽異步。最大的問題是阻塞,同步。每次請求都由程序執行并返回,這是同步的缺陷。這些都會被注冊在多路復用器上。多路復用器提供選擇已經就緒狀態任務的能力。并沒有采用的多路復用器,而是使用異步通道的概念。 Netty是一個提供異步事件驅動的網絡應用框架,用以快速開發高性能、高可靠的網絡服務器和客戶端程序。Netty簡化了網絡程序的開發,是很多框架和公司...
摘要:后改良為用線程池的方式代替新增線程,被稱為偽異步。最大的問題是阻塞,同步。每次請求都由程序執行并返回,這是同步的缺陷。這些都會被注冊在多路復用器上。多路復用器提供選擇已經就緒狀態任務的能力。并沒有采用的多路復用器,而是使用異步通道的概念。 Netty是一個提供異步事件驅動的網絡應用框架,用以快速開發高性能、高可靠的網絡服務器和客戶端程序。Netty簡化了網絡程序的開發,是很多框架和公司...
摘要:阻塞請求結果返回之前,當前線程被掛起。也就是說在異步中,不會對用戶線程產生任何阻塞。當前線程在拿到此次請求結果的過程中,可以做其它事情。事實上,可以只用一個線程處理所有的通道。 準備知識 同步、異步、阻塞、非阻塞 同步和異步說的是服務端消息的通知機制,阻塞和非阻塞說的是客戶端線程的狀態。已客戶端一次網絡請求為例做簡單說明: 同步同步是指一次請求沒有得到結果之前就不返回。 異步請求不會...
閱讀 1905·2021-11-25 09:43
閱讀 1405·2021-11-22 14:56
閱讀 3280·2021-11-22 09:34
閱讀 2010·2021-11-15 11:37
閱讀 2256·2021-09-01 10:46
閱讀 1396·2019-08-30 15:44
閱讀 2294·2019-08-30 13:15
閱讀 2393·2019-08-29 13:07