• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • BIO,NIO,AIO網絡編程——java

    標簽: JAVA學習筆記  aio  nio  網絡編程

    一、BIO

    阻塞輸入輸出,傳統得tcp和udp編程形式,服務端為每一個客戶端之間建立專線連接。

    前面得信息處理會影響后面得信息處理。

    二、NIO

    非阻塞輸入輸出。一個線程同時管理多個連接,減少線程多的壓力,不是真的異步操作。

    Selector:多路選擇器   Channel:通道     Buffer:緩沖區

    服務端方法:

    1.建立服務端通道并且在制定端口等待連接

    2.多路選擇器進行輪詢,并且提取出有動作得通道

    3.根據通道內得信息判斷是否是請求連接信息還是傳輸信息。如果是請求連接則同意連接。若是讀取信息則需要通過緩沖流讀取,寫入信息也是需要通過緩沖流進行。

    客戶端方法:

    1.請求連接

    2.進行寫入操作,寫入操作也是需要先過緩沖流區的。

    示例:

    package nio;
    
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    import java.util.Iterator;
    import java.util.Set;
    
    public class NioServer {
    
        public static void main(String[] args) throws IOException {
        	//1.建立服務端通道并且在制定端口等待連接
        	int port = 8001;
        	Selector selector = null;
        	ServerSocketChannel servChannel = null;
        	
        	try {
    			selector = Selector.open();
    			servChannel = ServerSocketChannel.open();
    			servChannel.configureBlocking(false);
    			servChannel.socket().bind(new InetSocketAddress(port), 1024);
    			servChannel.register(selector, SelectionKey.OP_ACCEPT);//將多入選擇器與通道進行綁定
    			System.out.println("服務器在8001端口守候");
    		} catch (IOException e) {
    			e.printStackTrace();
    			System.exit(1);
    		}
        	
        	while(true)
        	{
        		try {
        			selector.select(1000);//輪詢操作
        			Set<SelectionKey> selectedKeys = selector.selectedKeys();//取出需要處理的通道
        			Iterator<SelectionKey> it = selectedKeys.iterator();
        			SelectionKey key = null;
        			while (it.hasNext()) {
        				key = it.next();
        				it.remove();
        				try {
        					handleInput(selector,key);
        				} catch (Exception e) {
        					if (key != null) {
        						key.cancel();
        						if (key.channel() != null)
        							key.channel().close();
        					}
        				}
        			}
        		} 
        		catch(Exception ex)
        		{
        			ex.printStackTrace();    			
        		}
        		
        		try
        		{
        			Thread.sleep(500);
        		}
        		catch(Exception ex)
        		{
        			ex.printStackTrace();    			
        		}
        	}
        }
        
        public static void handleInput(Selector selector, SelectionKey key) throws IOException {
    
    		if (key.isValid()) {
    			// 處理新接入的請求消息
    			if (key.isAcceptable()) {
    				// Accept the new connection
    				ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
    				SocketChannel sc = ssc.accept();
    				sc.configureBlocking(false);
    				// Add the new connection to the selector
    				sc.register(selector, SelectionKey.OP_READ);
    			}
    			if (key.isReadable()) {
    				// Read the data
    				SocketChannel sc = (SocketChannel) key.channel();
    				ByteBuffer readBuffer = ByteBuffer.allocate(1024);
    				int readBytes = sc.read(readBuffer);
    				if (readBytes > 0) {
    					readBuffer.flip();
    					byte[] bytes = new byte[readBuffer.remaining()];
    					readBuffer.get(bytes);
    					String request = new String(bytes, "UTF-8"); //接收到的輸入
    					System.out.println("client said: " + request);
    					
    					String response = request + " 666";
    					doWrite(sc, response);
    				} else if (readBytes < 0) {
    					// 對端鏈路關閉
    					key.cancel();
    					sc.close();
    				} else
    					; // 讀到0字節,忽略
    			}
    		}
    	}
    
    	public static void doWrite(SocketChannel channel, String response) throws IOException {
    		if (response != null && response.trim().length() > 0) {
    			byte[] bytes = response.getBytes();
    			ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
    			writeBuffer.put(bytes);
    			writeBuffer.flip();
    			channel.write(writeBuffer);
    		}
    	}
    }
    
    package nio;
    
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.SocketChannel;
    import java.util.Iterator;
    import java.util.Set;
    import java.util.UUID;
    
    public class NioClient {
    
    	public static void main(String[] args) {
    
    		String host = "127.0.0.1";
    		int port = 8001;
    
    		Selector selector = null;
    		SocketChannel socketChannel = null;
    
    		try 
    		{
    			selector = Selector.open();
    			socketChannel = SocketChannel.open();
    			socketChannel.configureBlocking(false); // 非阻塞
    
    			// 如果直接連接成功,則注冊到多路復用器上,發送請求消息,讀應答
    			if (socketChannel.connect(new InetSocketAddress(host, port))) 
    			{
    				socketChannel.register(selector, SelectionKey.OP_READ);
    				doWrite(socketChannel);
    			} 
    			else 
    			{
    				socketChannel.register(selector, SelectionKey.OP_CONNECT);
    			}
    
    		} catch (IOException e) {
    			e.printStackTrace();
    			System.exit(1);
    		}
    
    		while (true) 
    		{
    			try 
    			{
    				selector.select(1000);
    				//函數功能(根據源碼上的注釋翻譯而來):選擇一些I/O操作
    				//已經準備好的管道。每個管道對應著一個key。這個方法
    				//是一個阻塞的選擇操作。當至少有一個通道被選擇時才返回。
    				//當這個方法被執行時,當前線程是允許被中斷的。
    				Set<SelectionKey> selectedKeys = selector.selectedKeys();
    				Iterator<SelectionKey> it = selectedKeys.iterator();
    				SelectionKey key = null;
    				while (it.hasNext()) 
    				{
    					key = it.next();
    					it.remove();
    					try 
    					{
    						//處理每一個channel
    						handleInput(selector, key);
    					} 
    					catch (Exception e) {
    						if (key != null) {
    							key.cancel();
    							if (key.channel() != null)
    								key.channel().close();
    						}
    					}
    				}
    			} 
    			catch (Exception e) 
    			{
    				e.printStackTrace();
    			}
    		}
    	
    
    		// 多路復用器關閉后,所有注冊在上面的Channel資源都會被自動去注冊并關閉
    //		if (selector != null)
    //			try {
    //				selector.close();
    //			} catch (IOException e) {
    //				e.printStackTrace();
    //			}
    //
    //		}
    	}
    
    	public static void doWrite(SocketChannel sc) throws IOException {
    		byte[] str = UUID.randomUUID().toString().getBytes();
    		ByteBuffer writeBuffer = ByteBuffer.allocate(str.length);
    		writeBuffer.put(str);
    		writeBuffer.flip();
    		sc.write(writeBuffer);
    	}
    
    	public static void handleInput(Selector selector, SelectionKey key) throws Exception {
    
    		if (key.isValid()) {
    			// 判斷是否連接成功
    			SocketChannel sc = (SocketChannel) key.channel();
    			if (key.isConnectable()) {
    				if (sc.finishConnect()) {
    					sc.register(selector, SelectionKey.OP_READ);					
    				} 				
    			}
    			if (key.isReadable()) {
    				ByteBuffer readBuffer = ByteBuffer.allocate(1024);
    				int readBytes = sc.read(readBuffer);
    				if (readBytes > 0) {
    					readBuffer.flip();
    					byte[] bytes = new byte[readBuffer.remaining()];
    					readBuffer.get(bytes);
    					String body = new String(bytes, "UTF-8");
    					System.out.println("Server said : " + body);
    				} else if (readBytes < 0) {
    					// 對端鏈路關閉
    					key.cancel();
    					sc.close();
    				} else
    					; // 讀到0字節,忽略
    			}
    			Thread.sleep(3000);
    			doWrite(sc);
    		}
    	}
    }
    

    三、AIO編程

    異步的輸入輸出操作,采用回調方法進行讀寫處理

    主要思想:通過AsynchronousServerSocketChannel建立服務端請求通道,并且通過bind綁定端口和地址,同時在accept函數中放入CompletionHandler異步處理類讓。異步處理類的主要是使該操作完成后就可以實現后續的任務,若成功則執行completed()函數,失敗或發生異常則執行failed函數。

    package aio;
    
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.CharBuffer;
    import java.nio.channels.AsynchronousChannelGroup;
    import java.nio.channels.AsynchronousServerSocketChannel;
    import java.nio.channels.AsynchronousSocketChannel;
    import java.nio.channels.CompletionHandler;
    import java.nio.charset.Charset;
    import java.nio.charset.CharsetDecoder;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class AioServer {
    
        public static void main(String[] args) throws IOException {  
        	AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open();   
            server.bind(new InetSocketAddress("localhost", 8001));  
            System.out.println("服務器在8001端口守候");
            
            //開始等待客戶端連接,一旦有連接,做26行任務
            server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {  
                @Override  
                public void completed(AsynchronousSocketChannel channel, Object attachment) {  
                	 server.accept(null, this); //持續接收新的客戶端請求
                	 
                     ByteBuffer buffer = ByteBuffer.allocate(1024); //準備讀取空間
                     //開始讀取客戶端內容,一旦讀取結束,做33行任務
                     channel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
                         @Override
                         public void completed(Integer result_num, ByteBuffer attachment) {
                             attachment.flip(); //反轉此Buffer 
                             CharBuffer charBuffer = CharBuffer.allocate(1024);
                             CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
                             decoder.decode(attachment,charBuffer,false);
                             charBuffer.flip();
                             String data = new String(charBuffer.array(),0, charBuffer.limit());
                             System.out.println("client said: " + data);
                             channel.write(ByteBuffer.wrap((data + " 666").getBytes())); //返回結果給客戶端
                             try{
                                 channel.close();
                             }catch (Exception e){
                            	 e.printStackTrace();
                             }
                         }
          
                         @Override
                         public void failed(Throwable exc, ByteBuffer attachment) {
                             System.out.println("read error "+exc.getMessage());
                         }
                     });
                     
    
                }  
      
                @Override  
                public void failed(Throwable exc, Object attachment) {  
                    System.out.print("failed: " + exc.getMessage());  
                }  
            });  
    
            while(true){
            	try {
    				Thread.sleep(5000);
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
            }
        }  
    }
    
    package aio;
    
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.CharBuffer;
    import java.nio.channels.AsynchronousSocketChannel;
    import java.nio.channels.CompletionHandler;
    import java.nio.charset.Charset;
    import java.nio.charset.CharsetDecoder;
    import java.util.UUID;
    
    
    public class AioClient {
    
    	public static void main(String[] a) {
    		try
    		{
    			AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
    			
    			//18行連接成功后,自動做20行任務
    			channel.connect(new InetSocketAddress("localhost", 8001), null, new CompletionHandler<Void, Void>() {
    
    				public void completed(Void result, Void attachment) {
    					String str = UUID.randomUUID().toString();
    					
    					//24行向服務器寫數據成功后,自動做28行任務
    					channel.write(ByteBuffer.wrap(str.getBytes()), null,
    							new CompletionHandler<Integer, Object>() {
    
    								@Override
    								public void completed(Integer result, Object attachment) {
    									try {
    										System.out.println("write " + str + ", and wait response");
    										//等待服務器響應
    										ByteBuffer buffer = ByteBuffer.allocate(1024); //準備讀取空間
    						                 //開始讀取服務器反饋內容,一旦讀取結束,做39行任務
    										channel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
    						                     @Override
    						                     public void completed(Integer result_num, ByteBuffer attachment) {
    						                         attachment.flip(); //反轉此Buffer 
    						                         CharBuffer charBuffer = CharBuffer.allocate(1024);
    						                         CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
    						                         decoder.decode(attachment,charBuffer,false);
    						                         charBuffer.flip();
    						                         String data = new String(charBuffer.array(),0, charBuffer.limit());
    						                         System.out.println("server said: " + data);
    						                         try{
    						                             channel.close();
    						                         }catch (Exception e){
    						                        	 e.printStackTrace();
    						                         }
    						                     }
    						      
    						                     @Override
    						                     public void failed(Throwable exc, ByteBuffer attachment) {
    						                         System.out.println("read error "+exc.getMessage());
    						                     }
    						                 });
    						                 
    										channel.close();
    									} catch (Exception e) {
    										e.printStackTrace();
    									}
    								}
    
    								@Override
    								public void failed(Throwable exc, Object attachment) {
    									System.out.println("write error");
    								}
    
    							});
    				}
    
    				public void failed(Throwable exc, Void attachment) {
    					System.out.println("fail");
    				}
    
    			});
    			Thread.sleep(10000);
    		}
    		catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }

    參考中國大學mooc《java核心技術》

    版權聲明:本文為weixin_43698704原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/weixin_43698704/article/details/104138147

    智能推薦

    【Java網絡編程】基于BIO/NIO/AIO的多人聊天室(五):AIO聊天室

    課程《一站式學習Java網絡編程 全面理解BIO/NIO/AIO》的學習筆記(五): 異步調用機制 & AIO編程模型 & 基于AIO的多人聊天室實現 源碼地址:https://github.com/NoxWang/web-program 【Java網絡編程】基于BIO/NIO/AIO的多人聊天室(一):java IO與內核IO 【Java網絡編程】基于BIO/NIO/AIO的多人...

    一站式學習Java網絡編程 全面理解BIO_NIO_AIO,學習手記(六)

    大家好,我是方圓 把這篇肝完就休息! 目錄 1. NIO模型分析 2. 聊天室項目代碼重點知識 2.1 服務器端 2.1.1 字段 2.1.2 主方法 2.1.3 處理方法 2.1.4 轉發消息方法 2.1.5 接收消息方法 2.2 客戶端 2.2.1 字段 2.2.2 主方法 2.2.3 處理方法 2.2.4 接收方法 2.2.5 發送方法 3. 測試結果 4. 完整代碼 4.1 服務器端 4....

    一站式學習Java網絡編程 全面理解BIO_NIO_AIO,學習手記(七)

    大家好,我是方圓 目錄 1. 在系統層面分析IO模型 1.1 BIO模型 1.2 NIO模型 1.2.1 IO多路復用 1.3 AIO模型(異步IO) 2. 異步調用機制 2.1 AIO中的異步操作 2.2 通過Future進行異步調用 2.3 通過CompletionHandler(多用) 3. 實戰(回音服務器) 3.1 服務器端 3.1.1 字段 3.1.2 主方法 3.1.3 Accept...

    一站式學習Java網絡編程 全面理解BIO_NIO_AIO,學習手記(八)

    大家好,我是方圓 目錄 1. AIO模型分析 2. 聊天室分析 2.1 服務器端 2.1.1 字段 2.1.2 主方法 2.1.3 AcceptHandler 2.1.4 ClientHandler(處理讀寫請求) 2.1.5 添加和刪除用戶 2.1.6 接收和轉發方法 2.2 客戶端 2.2.1 主方法 2.2.2 發送消息 2.2.3 用戶的輸入線程 3. 測試結果 4. 完整代碼 4.1 服...

    一站式學習Java網絡編程 全面理解BIO_NIO_AIO,學習手記(四)

    大家好,我是方圓 BIO聊天室很好實現吶 目錄 1. 概念圖解 1.1 偽異步的優化 2. 聊天服務器中的要點 2.1 字段 2.2 轉發消息方法 2.3 添加客戶方法 2.4 移除客戶方法 2.5 服務器主線程任務 2.6 服務器處理線程任務 3. 聊天室客戶端要點 3.1 向服務端發送消息,讓服務器轉發給其他人 3.2 接收服務端的消息 3.3 主線程任務 3.4 處理線程任務 4. 測試結果...

    猜你喜歡

    一站式學習Java網絡編程 全面理解BIO_NIO_AIO,學習手記(四)

    BIO聊天室很好實現吶 目錄 1. 概念圖解 1.1 偽異步的優化 2. 聊天服務器中的要點 2.1 字段 2.讀入數據 總結 1. 概念圖解 BIO模型:客戶端每有一個請求,服務端都要有一個線程來單獨處理這個請求,典型的 一請求一應答 ,java 1.4版本之前 對于聊天室服務器,它有多個線程,其中一個為圖上的 Acceptor線程(ChatServer),它實現的就是對來自客戶端的請求不斷響應...

    一站式學習Java網絡編程 全面理解BIO_NIO_AIO,學習手記(三)

    1.BIO阻塞模型 2. 簡單實戰演示 2.1 服務器 2.2 客戶端 2.3 響應結果 1.BIO阻塞模型 簡述BIO模型中服務端與客戶端的響應過程 服務器serverSocket先要和端口進行綁定 綁定完成后,執行accept方法,等待客戶端的連接,這個方法是阻塞式調用,也就是說,要一直等待客戶端的連接響應,不做其他事情,一直等,(被阻塞的還有 InputStream.read()、Outpu...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    精品国产乱码久久久久久蜜桃不卡