Java IO、NIO、AIO

IO、NIO、AIO

Socket

在應用程序中通常使用套接字來向網絡發出請求或者應答網絡請求。

Socket(套接字):用於唯一標識網絡上的某臺主機上的某個進程(服務),Socket就是IP:Port的形式,一個IP地址和一個端口號來標識。

Java中Socket和ServerSocket類庫位於Java.net包中,ServerSocket用於服務器端,Socket則在建立網絡鏈接時使用,也就是客戶端,在連接完成後應用程序兩端都會產生Socket實例。注意:雖然有客戶端和服務端的概念,但是對於網絡連接來說,套接字是平等的

建立網絡連接:

  1. 服務器監聽:服務端打開端口,用於監聽連接請求。
  2. 客戶端請求:客戶端使用套接字來請求連接。
  3. 服務端確認:監聽到連接請求後,響應客戶端的請求,並建立一個新的進程用於響應,然後將服務端的套接字發送回客戶端。
  4. 一旦客戶端確認了,就建立好連接,雙方開始通信。客戶端仍然處於監聽狀態。

網絡編程的基於模型Client/Server模型,三次握手,基於TCP的連接。

IO

直接使用Socket建立連接,進行通信的方式就是BIO(阻塞式IO)在建立TCP響應的時候,對於服務端端口是阻塞的。當有一個客戶端進行訪問時,其他的客戶端是不能訪問的。

優化方案:服務端使用線程池管理,僞異步。但由於使用的是阻塞隊列,所以是僞異步的。

public class Server {
final static int PORT = 8765;
public static void main(String[] args) {
	ServerSocket server = null;
	BufferedReader in = null;
	PrintWriter out = null;
	try {
	server = new ServerSocket(PORT);
	System.out.println("server start");
	Socket socket = null;
	HandlerExecutorPool executorPool = new 		HandlerExecutorPool(50, 1000);
	while(true){
		socket = server.accept();
		//使用線程池進行操作實現異步
		executorPool.execute(new ServerHandler(socket));
		}
		} catch (Exception e) {
			e.printStackTrace();
		} 

NIO

NIO有兩種說法new IO和Not—block IO。習慣於非阻塞IO。注意NIO只是非阻塞但不是異步的。

本質就是避免了TCP連接的3次握手操作,減少連接的開銷。

核心是通道和多路複用器:

通道:雙向的通信方式,具有讀寫的能力,同時具有狀態位。

多路複用器:也就是seletor。提供輪詢管理通道的能力。所有通道都由selector管理。每一個在複用器上註冊了的管道都會被分配一個key用作標識,複用器也會通過key去找到相應的管道。

在這裏插入圖片描述

每個管道具有的狀態碼:

SelectionKey.OP_CONNECT 連接狀態

SelectionKey.OP_ACCEPT 阻塞狀態

SelectionKey.OP_READ 可讀狀態

SelectionKey.OP_WRITE 可寫狀態

步驟:

創建NIO服務器的主要步驟
    (1)打開ServerSocketChannel,監聽客戶端連接
    (2)綁定監聽端口,設置連接爲非阻塞模式
    (3)創建Reactor線程,創建多路複用器並啓動線程
     (4)將ServerSocketChannel註冊到Reactor線程中的Selector上,監聽ACCEPT事件
     (5)Selector輪詢準備就緒的key
     (6)Selector監聽到新的客戶端接入,處理新的接入請求,完成TCP三次握手,簡歷物理鏈路
     (7)設置客戶端鏈路爲非阻塞模式
     (8)將新接入的客戶端連接註冊到Reactor線程的Selector上,監聽讀操作,讀取客戶端發送的網絡消息
     (9)異步讀取客戶端消息到緩衝區
     (10)對Buffer編解碼,處理半包消息,將解碼成功的消息封裝成Task
     (11)將應答消息編碼爲Buffer,調用SocketChannel的write將消息異步發送給客戶端

AIO

AIO編程,在NIO基礎上引入了異步通道的概念,提供異步文件和異步套接字通道的實現,從而在真正意義上實現了異步非阻塞。核心是AsynchronousServerScoketChannel和AsynchronousScoketChanel

核心:

//客戶端:
executorService = Executors.newCachedThreadPool();

//創建線程組

threadGroup = AsynchronousChannelGroup.withCachedThreadPool(executorService, 1);

//創建服務器通道

assc = AsynchronousServerSocketChannel.open(threadGroup);

//進行綁定

assc.bind(new InetSocketAddress(port));

System.out.println("server start , port : " + port);

//進行阻塞

assc.accept(this, new ServerCompletionHandler());

//一直阻塞 不讓服務器停止

Thread.sleep(Integer.MAX_VALUE);

//handler
public void completed(AsynchronousSocketChannel asc, Server attachment) {

//當有下一個客戶端接入的時候 直接調用Server的accept方法,這樣反覆執行下去,保證多個客戶端都可以阻塞(沒有遞歸上限),1.7以後AIO才實現了異步非阻塞

attachment.assc.accept(attachment, this);

read(asc);

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章