java中NIO程式設計另一種實現超實用
除了普通的Socket與ServerSocket實現的阻塞式通訊外,Java提供了非阻塞式通訊的NIO API。先看一下NIO的實現原理。
從圖中可以看出,伺服器上所有Channel(包括ServerSocketChannel和SocketChannel)都需要向Selector註冊,而該Selector則負責監視這些Socket的IO狀態,當其中任意一個或者多個Channel具有可用的IO操作時,該Selector的select()方法將會返回大於0的整數,該整數值就表示該Selector上有多少個Channel具有可用的IO操作,並提供了selectedKeys()方法來返回這些Channel對應的SelectionKey集合。正是通過Selector,使得伺服器端只需要不斷地呼叫Selector例項的select()方法即可知道當前所有Channel是否有需要處理的IO操作。
看個demo
NClient.java
- 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.nio.charset.Charset;
-
import java.util.Scanner;
- publicclass NClient {
- //定義檢測SocketChannel的Selector物件
- private Selector selector=null;
- //定義處理編碼和解碼的字符集
- private Charset charset=Charset.forName("UTF-8");
- //客戶端SocketChannel
- private SocketChannel sc=null;
- publicvoid init() throws IOException{
-
selector=Selector.open();
- InetSocketAddress isa=new InetSocketAddress("127.0.0.1",30000);
- //呼叫open靜態方法建立連線到指定主機的SocketChannel
- sc=SocketChannel.open(isa);
- //設定該sc以非阻塞方式工作
- sc.configureBlocking(false);
- //將Socketchannel物件註冊到指定Selector
- sc.register(selector, SelectionKey.OP_READ);
- //啟動讀取伺服器端資料的執行緒
- new ClientThread().start();
- //建立鍵盤輸入流
- Scanner scan=new Scanner(System.in);
- while(scan.hasNextLine()){
- //讀取鍵盤輸入
- String line=scan.nextLine();
- //將鍵盤輸入的內容輸出到SocketChannel中
- sc.write(charset.encode(line));
- }
- }
- //定義讀取伺服器資料的執行緒
- privateclass ClientThread extends Thread{
- publicvoid run(){
- try{
- while(selector.select()>0){
- //遍歷每個有可用IO操作Channel對應的SelectionKey
- for(SelectionKey sk:selector.selectedKeys()){
- //刪除正在處理的SelectionKey
- selector.selectedKeys().remove(sk);
- //如果該SelectionKey對應的Channel中有可讀的資料
- if(sk.isReadable()){
- //使用NIO讀取channel中的資料
- SocketChannel sc=(SocketChannel) sk.channel();
- ByteBuffer buff=ByteBuffer.allocate(1024);
- String content="";
- while(sc.read(buff)>0){
- //sc.read(buff);
- buff.flip();
- content+=charset.decode(buff);
- }
- //列印輸出讀取的內容
- System.out.println("聊天資訊"+content);
- //為下一次讀取做準備
- sk.interestOps(SelectionKey.OP_READ);
- }
- }
- }
- }catch(IOException ex){
- ex.printStackTrace();
- }
- }
- }
- publicstaticvoid main(String[]args) throws IOException{
- new NClient().init();
- }
- }
NServer.java
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import java.nio.ByteBuffer;
- import java.nio.channels.Channel;
- import java.nio.channels.SelectionKey;
- import java.nio.channels.Selector;
- import java.nio.channels.ServerSocketChannel;
- import java.nio.channels.SocketChannel;
- import java.nio.charset.Charset;
- publicclass NServer {
- //用於檢測所有Channel狀態的Selector
- private Selector selector=null;
- //定義實現編碼、解碼的字符集物件
- private Charset charset=Charset.forName("UTF-8");
- publicvoid init() throws IOException{
- selector=Selector.open();
- //通過open方法來開啟一個未繫結的ServerSocketChannel例項
- ServerSocketChannel server=ServerSocketChannel.open();
- InetSocketAddress isa=new InetSocketAddress("127.0.0.1",30000);
- //將該ServerSocketChannel繫結到指定ip地址
- server.socket().bind(isa);
- //設定ServerSocket以非阻塞方式工作
- server.configureBlocking(false);
- //將server註冊到指定Selector物件
- server.register(selector, SelectionKey.OP_ACCEPT);
- while(selector.select()>0){
- //依次處理selector上的每個已選擇的SelectionKey
- for(SelectionKey sk:selector.selectedKeys()){
- //從selector上的已選擇Key集中刪除正在處理的SelectionKey
- selector.selectedKeys().remove(sk);
- //如果sk對應的通訊包含客戶端的連線請求
- if(sk.isAcceptable()){
- //呼叫accept方法接受連線,產生伺服器端對應的SocketChannel
- SocketChannel sc=server.accept();
- //設定採用非阻塞模式
- sc.configureBlocking(false);
- sc.register(selector, SelectionKey.OP_READ);
- //將sk對應的Channel設定成準備接受其他請求
- sk.interestOps(SelectionKey.OP_ACCEPT);
- }
- //如果sk對應的通道有資料需要讀取
- if(sk.isReadable()){
- //獲取該SelectionKey對應的Channel,該Channel中有可讀的資料
- SocketChannel sc=(SocketChannel) sk.channel();
- //定義準備之星讀取資料的ByteBuffer
- ByteBuffer buff=ByteBuffer.allocate(1024);
- String content="";
- //開始讀取資料
- try{
- while(sc.read(buff)>0){
- buff.flip();
- content+=charset.decode(buff);
- }
- //列印從該sk對應的Channel裡讀到的資料
- System.out.println("=========="+content);
- //將sk對應的Channel設定成準備下一次讀取
- sk.interestOps(SelectionKey.OP_READ);
- //如果捕捉到該sk對應的channel出現異常,即表明該channel對應的client出現了
- //異常,所以從selector中取消sk的註冊
- }catch(IOException e){
- //從Selector中刪除指定的SelectionKey
- sk.cancel();
- if(sk.channel()!=null){
- sk.channel().close();
- }
- }
- //如果content的長度大於0,即聊天資訊不為空
-
相關推薦
java中NIO程式設計另一種實現超實用
除了普通的Socket與ServerSocket實現的阻塞式通訊外,Java提供了非阻塞式通訊的NIO API。先看一下NIO的實現原理。 從圖中可以看出,伺服器上所有Channel(包括ServerSocketChannel和SocketCha
Java模版方法的另一種實現
pan strategy 全部 相關 必須 rod () 抽象方法 rate 面試荔枝FM杯具,遂死磕AQS途中發現一個有趣的模版用法,記下來。 模版方法是很重要的設計模式,在數據訪問層、眾多的插件接口都可見其影子,一般的實現都是在模版中定義抽象方法並使用其方法進行
java 多執行緒的一種實現方式
private ThreadPoolExecutor threadPoolExecutor; /** * 獲取執行緒池 * @return */ private ThreadPoolExecutor getThreadPoolExecutor(){
吸頂效果的另一種實現
前面介紹過一篇文章,是使用ItemDecoration來實現吸頂效果,使用起來很解耦,簡單,方便,但是優缺點是拓展性比較差,今天就通過另一種方式來實現吸頂效果,並且吸頂欄可以高度制定佈局和互動,步入正題,下面來實現它,先看看效果圖: 一、實現原理 頭部的內容位於R
物聯網應用中的數字孿生——一種實現物聯網數字孿生的全面的解決方案
原文連結:http://www.oracle.com/us/solutions/inter...twins-for-iot-apps-wp-3491953.pdf 轉載於:https://blog.csdn.net/steelren/article/details/79198165 簡介
101889I (LCA的另一種實現)
題意: Q次詢問,每次詢問必須包含特定邊的最小生成樹。 思路: 考慮 最淳樸的最小生成樹,如果加了一條特定邊,肯定是構成了一個環,那麼環外的邊肯定是不變的,要不然,根本就不可能選外面的那些邊了, 所以我們現在就是求這個環上的最小 生成樹,肯定是找樹上之前的 兩個點之
利用IAT匯出OpenGL函式:OpenGL Loader的另一種實現辦法
利用這種辦法可以用50KB的DLL匯出OpenGL 3.3版本所有Core Profile函式, DLL比GLEW小很多, 根據glcorearb.h自動生成的程式碼與glLoadGen生成的程式碼差不多, 這部分程式碼包含的函式都是空實現,結合__declspec(dllexport,
載入一個類時,其內部類是否同時被載入?引申出單例模式的另一種實現方式...
載入一個類時,其內部類是否同時被載入?下面我們做一個實驗來看一下。public class Outer { static { System.out.println("load outer class..."); } //靜態內部類 sta
載入一個類時,其內部類是否同時被載入?引申出單例模式的另一種實現方式
載入一個類時,其內部類是否同時被載入?下面我們做一個實驗來看一下。 Java程式碼 1. public class Outer { 2. static { 3. System.out.println("load o
Java中文鍵樹的一種實現(附帶模糊查詢功能)
首先在文章的開頭宣告一下哈,本文只是介紹一種Java蠻力鍵樹的實現,並沒有什麼高深的資料結構,所以資料量不超過百萬字元的可以參考,資料量太大的另請高明吧。另外,後面的鍵樹程式碼實際上不僅適用於中文儲存和查詢,只要是字串形式的資料都可以儲存。比如:“鋤禾日當午”、“a+你好啊234#jfjf”這樣形式
程序和程式關係類比/ java中執行緒是哪種實現【清華大學】作業系統
本文分三個小節 1 執行緒模型 2 執行緒的實現 3 java中執行緒是使用者執行緒,核心執行緒,輕量級程序??? 3.1 臨界區 互斥 3.2 訊號量 管程 前兩小節是來自作業系統。 第三小節:看到作業系統中執行緒實現的三種方式,忽然想起我以
分頁的另一種實現-不用額外請求
情景:千里碼有些最優化題目的旁邊會有一個排行榜,用來展示不同的答案。比如[Uber打車匹配](http://www.qlcoder.com/task/7596) 這裡的答題人數並不多,但是[老王
STM32F103按鍵操作的另一種實現——狀態機
#ifndef _KEY_H_ #define _KEY_H_ #include "HAL_gpio.h" // 換成STM32F103對應的GPIO庫 #include "type.h" // type.h主要是一些型別的重新命名 #define KEY_U
java中線性表的兩種實現方式區別
注意:線性表的兩種實現->順序實現和鏈式實現 線性表的兩種實現 順序表 連結串列 空間效能 順序表的儲存空間是靜態分佈的,需要一個固定的陣列,總有部分陣列元素要浪費 連結串列的儲存空間是動態分佈,因此不會有空間被浪費。但由於連結串列需要額外的空間來
另一種實現非阻塞網路通訊的方法———使用libev
背景:最近終於開始了我的實習生之路,本來在進公司之前還比較緊張,儘管拿到了offer,因為畢竟這是一個新的起點,一開始從學生到員工這個身份的轉變讓我有些不太適應,但是還好在公司裡遇到了人超級好的軟體經理Alex以及其他精明能幹的小夥伴們,所以這個過渡時間也很快。 一開始Al
Java中阻塞佇列的幾種實現方式
1.wait()和notify()方式(摘自:https://segmentfault.com/a/1190000000373535) 阻塞佇列與普通佇列的區別在於,當佇列是空的時,從佇列中獲取元素的操作將會被阻塞,或者當佇列是滿時,往佇列裡新增元素的操作會被阻塞。試圖從
嘗試新思路——CError的另一種實現方式
程式碼如下: #ifndef __MYERROR_H__ #define __MYERROR_H__ #include "Error.h" #include <map> #include
Sticky Header的另一種實現方法
使用Sticky Header的list單個item一般情況下使用的資料結構是 {data:"what's inside", category:"section name"} 這樣儲存其實是浪費了很多的空間,因為category的名字被儲存的多次。在移動環境
縮放到選中的另一種實現
Dim pDoc As IMxDocumentSet pDoc = ThisDocumentDim pMap As IMapSet pMap = pDoc.FocusMapDim pLayer As IFeatureLayerDim pFSel As IFeatureSele
代理的另一種實現方式
代理相信大家都很熟悉了。不過還是說下吧。 舉個例子: // // A.h // Created by XX // @protocol SomeDelegate <NSObject> - (void)someMethod:(UIVi