基於java的nio訊息實現方式優缺點分析及示例程式碼說明
轉:http://www.xwood.net/_site_domain_/_root/5870/5874/t_c255146.html
java nio在jdk1.4版本中加入新io的功能,所有涉及類都在java.nio包下,改寫了原有客戶端伺服器一對一執行緒阻塞等待的方式,通過事件驅動的方式監聽訊息,實際上通常採用Reactor模式2,提高系統整體資源利用率,下面具體分析對比io及nio同樣實現訊息方式的優缺點,同時對nio的實現方式具體分析及程式碼示例
一、阻塞I/O缺點
原i/o操作都是以字元為單位進行讀寫(雖然上層使用高階流進行封裝不去直接處理位元組流,但最終都是呼叫底層處理字元流),該操作是一次一個位元組的處理資料,速度有點慢,通過InputStream的read()阻塞方法從流中讀取資料,如資料來源沒資料,就會一直等到下去,每一個客戶端伺服器都會建立一個執行緒等到上面的等到阻塞操作,其他程式佔用,所以造成系統資源無效浪費,不能有效的利用,這是新io非阻塞的io需要解決的問題,具體缺點如下:
1.系統資源利用率低,浪費硬體資源(見圖1-1)-大部分執行緒都是在阻塞等到中(詳細程式碼見“”)
ServerSocket ss= new ServerSocket( 8080 );
System.out.println( "伺服器已啟動,等到客戶端連線" );
while ( true ){
//監聽並接受客戶端連線,注意該方法有阻塞性
Socket s=ss.accept();
//將客戶端的Socket連線新增到一個Vector集合
vector.add(s);
System.out.println( "客戶端連線成功!" +s);
new MySocketOpt(s).start();
}
|
2.系統穩定度不夠,服務端響應隨著客戶端的增加延時增加,每一個客戶端需要建立一個執行緒,當到達一定的限制時,會是系統無法響應
圖1-1
二、非阻塞NIO分析
NIO基於原有的I/O的改進和擴充套件,NIO與原有I/O不同,它是基於特殊緩衝區塊(Buffer)進行高效的I/O操作。NIO的快取區塊與普通的緩衝區不同,它是一塊連續的空間,它記憶體的分配不在Java的堆疊中,不受Java記憶體回收的影響;它的實現不是存Java的程式碼,而是原生代碼,這樣作業系統可以直接與緩衝區進行互動,Java程式只需要完成對緩衝區的讀寫,而後續操作由作業系統完成。非同步通道Channel(又稱頻道)是NIO的新特徵,通過Channel,Java應用程式能夠更好地與作業系統的I/O服務結合起來,充分利用Buffer緩衝區,更高效地完成I/O操作。NIO新特徵具體體現方面如下:
1. 更靈活的可伸縮的I/O介面(scalable I/O),包括I/O抽象Channels的出現以及新的多元(multiplexed),非阻塞(non-blocking)的I/O機制。可以更靈活方便的構建產品級的應用服務,對於成千上萬的客戶端連線變動更可用,從而有效地利用多個處理器資
2. 快速緩衝(fast buffered)的二進位制和字元I/O介面。快速緩衝的二進位制I/O API使得使用者可以容易的編寫出操作檔案流或者二進位制資料流的高效能程式碼。而快速快取的字元I/O API使得使用者可以高效地處理字元流和檔案,此外它還將正則表示式引入到Java平臺中來格式化使用者的輸入與輸出
3. 字符集的編碼器和解碼器。這些字符集轉換API使得使用者可以直接訪問作業系統內建的字符集轉換器,同時還支援那些外來的轉換器
4. 基於Perl風格正則表示式的匹配機制(A pattern-matching facility based on Perl-style regular expressions)
5. 改良的檔案系統介面,支援鎖定和記憶體對映(locks and memory mapping).此特徵使得使用者可以更加容易地處理各種檔案系統操作中出現的問題,同時使得使用者可以更加高效地訪問大量的檔案屬性集。此外如果使用者確實需要,還可以訪問與平臺相關的一些特徵。最後,它還提供對非本地檔案系統的支援,例如網路檔案系統(network filesystems)。
6. 新的I/O違例類可以使使用者更加有針對性地來處理各種I/O錯誤,讓使用者能夠在各種平臺上一致地對待這些錯誤。
7. 增加了對併發的支援,NIO類中的大部分方法都支援多個併發的執行緒
三、NIO具體工作原理
服務端專門有一個執行緒負責處理所有註冊事件,並負責分發(wait/notify),但事件被觸發時,分配獨立執行緒完成響應過程(讀取資料、解碼、計算處理、編碼、傳送相應),如圖3-1所示。java NIO採用雙向通道(channel)進行資料傳輸,不是像之前I/O採用單向流(stream),並在通道上註冊我們需要的事件:服務端接收客戶端連線事件:SelectionKey.OP_ACCEPT(16)、客戶端連線服務端事件:SelectionKey.OP_CONNECT(8)、讀事件:SelectionKey.OP_READ(1)、寫事件:SelectionKey.OP_WRITE(4)。
圖3-1
伺服器端和客戶端各次有自己的時間選擇物件Selector,它們通過在通道物件channel上註冊想要的事件,進行建立會話通道,到事件發生時,將進行處理響應結果給對方,如下圖3-2
圖3-1
四、程式碼示例
客戶端部分
客戶端部分由client.java、ClientThread.java類組成,具體如下:
import java.io.*;
public class Client {
public static void main(String[] args) {
ClientThread client = new ClientThread();
client.start();
BufferedReader sin = new BufferedReader(
new InputStreamReader(System.in));
try {
String readline;
while ((readline = sin.readLine()) != null ) {
if (readline.equals( "bye" )) {
client.close();
System.exit( 0 );
}
client.send(readline);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
|
服務端部分
服務端部分包括Server.java,具體如下:
import
java.io.IOException;
import
java.net.InetSocketAddress;
import
java.nio.ByteBuffer;
import
java.nio.CharBuffer;
import
java.nio.channels.Selector;
import
java.nio.channels.ServerSocketChannel;
import
java.nio.channels.SelectionKey;
import
java.nio.channels.SocketChannel;
import
java.nio.charset.Charset;
import
java.nio.charset.CharsetDecoder;
import
java.nio.charset.CharsetEncoder;
import
java.util.Iterator;
public
class
Server {
private
static
final
int
SERVERPORT=
8890
;
public
static
void
main(String[] args) {
Selector selector =
null
;
ServerSocketChannel server =
null
;
try
{
selector = Selector.open();
server = ServerSocketChannel.open();
InetSocketAddress ip =
new
InetSocketAddress(SERVERPORT);
server.socket().bind(ip);
server.configureBlocking(
false
);
server.register(selector,SelectionKey.OP_ACCEPT);
System.out.println(
"伺服器開始接受客戶端連線"
);
while
(
true
){
try
{
selector.select();
}
catch
(Exception e) {
}
Iterator<SelectionKey>it = selector.selectedKeys().iterator();
while
(it.hasNext()){
SelectionKey key = it.next();
it.remove();
if
(key.isAcceptable()){
ServerSocketChannel server2 = (ServerSocketChannel)key.channel();
SocketChannel channel = server2.accept();
channel.configureBlocking(
false
);
channel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);
System.out.println(
"客戶端:"
+ channel.socket().getInetAddress().getHostName() +
":"
+ channel.socket().getPort() +
" 連線上了"
);
}
if
(key.isReadable()){
SocketChannel channel = (SocketChannel)key.channel();
CharsetDecoder decoder = Charset.forName(
"UTF-8"
).newDecoder();
ByteBuffer buffer = ByteBuffer.allocate(
50
);
try
{
channel.read(buffer);
}
catch
(IOException e){
// 客戶端異常斷開連線
System.out.println(
"客戶端:"
+ channel.socket().getInetAddress().getHostName() +
":"
+ channel.socket().getPort() +
" 已斷開連線"
);
channel.close();
continue
;
}
buffer.flip();
String msg = decoder.decode(buffer).toString();
if
(msg.equals(
"退出[email protected]#$%"
)) {
// 客戶端主動斷開連線
System.out.println(
"客戶端:"
+ channel.socket().getInetAddress().getHostName() +
":"
+ channel.socket().getPort() +
" 已斷開連線"
);
channel.close();
continue
;
}
System.out.println(
channel.socket().getInetAddress().getHostName() +
":"
+ channel.socket().getPort() +
":"
+ msg);
if
(key.isWritable()) {
// System.out.println("可寫");
CharsetEncoder encoder = Charset.forName(
"UTF-8"
).newEncoder();
try
{
channel.write(encoder.encode(CharBuffer.wrap(
"server receive your message "
)));
}
catch
(IOException e) {
// TODO: handle exception
System.out.println(
"寫入io錯誤"
);
}
}
}
}
}
}
catch
(IOException e){
e.printStackTrace();
}
finally
{
try
{
selector.close();
server.close();
}
catch
(IOException e){}
}
}
}
相關推薦
基於java的nio訊息實現方式優缺點分析及示例程式碼說明
轉:http://www.xwood.net/_site_domain_/_root/5870/5874/t_c255146.html java nio在jdk1.4版本中加入新io的功能,所有涉及類都在java.nio包下,改寫了原有客戶端伺服器一對一執行緒阻塞等待的方式
基於DLNA的UPNP協議的分析及實現
1 引言 UPnP 全名是Universal Plug and Play,主要是微軟在推行的一個標準。簡單的來說,UPnP 最大的願景就是希望任何裝置只要一接上網路,所有在網路上的裝置馬上就能知道有新裝置加入,這些裝置彼此之間能互相溝通,更能直接使用或控制它,一切都不需要設定,完全的Plug and Pla
Android中實現IPC的幾種方式詳細分析及比較
1.使用Bundle ----> 用於android四大元件間的程序間通訊android的四大元件都可使用Bundle傳遞資料 所以如果要實現四大元件間的程序間通訊 完全可以使用Bundle來實現 簡單方便 2.使用檔案共享 ---->用於單執行緒讀寫
【外貿推廣科普】主流外貿推廣渠道優缺點分析及實操之展會推廣
外貿推廣 外貿推廣渠道 展會推廣 國內外每年都有很多展會,在前文講到的那些B2B/B2C平臺還沒出來的時候,參加外貿展會是當時最有效的外貿推廣方式了,通過展會直接成交的快感在當時很多外貿人都有享受過。而且展會對於打造品牌有著先天的優勢,即使現在參展的效果不理想,但對很多企業來說,想在海外提
【外貿推廣科普】主流外貿推廣渠道優缺點分析及實操之平臺推廣
外貿推廣 外貿推廣渠道 平臺推廣 B2B B2C 外貿推廣,也就是海外推廣的渠道有很多,比較主流的有6種:1、B2B/B2C平臺推廣(B2B如阿裏國際站、made in china等(國外B2B請看最全外貿B2B平臺列表),B2C如速賣通、亞馬遜等) B2B平臺推廣是外貿推廣渠道中眾所周知
Python GUI程式設計實現方式優缺點對比
從 Python 語言的誕生之日起,就有許多優秀的 GUI 工具集整合到 Python 當中,這些優秀的 GUI 工具集,使得 Python 也可以在圖形介面程式設計領域當中大展身手,由於
隨機森林的原理分析及Python程式碼實現
轉載地址:https://blog.csdn.net/flying_sfeng/article/details/64133822/在講隨機森林前,我先講一下什麼是整合學習。整合學習通過構建並結合多個分類器來完成學習任務。整合學習通過將多個學習器進行結合,常可獲得比單一學習器更
0002演算法--------整數劃分問題演算法分析及JAVA程式碼完美實現
整數劃分演算法分析以及JAVA程式碼完美實現 一、問題描述 整數劃分:將正整數n表示成一系列正整數只和,n = n1 + n2 + …… + nk,其中n1 >= n2 >= nk &g
BP神經網路原理分析及c++程式碼實現(上)
本部落格所述BP神經網路,是本人研究總結的結果,希望對您有所幫助,當然,如果有需要,大家可以互相交流。 設計一個BP神經網路類,來實現一個BP神經網路。要求輸入層節點數、隱層數、隱層節點數、輸出層節點數、傳遞函式、演算法等等可以由使用者自主設定。 神經網路
BP神經網路原理分析及c++程式碼實現(下)
為了方便廣大使用者的使用,本人將BP神經網路寫成了一個BPNNS類,這樣使用者們可以很方便的將此類潛入到自己的工程當中,此類的具體的使用規則,下面會介紹。 /*********************************************************
Go/Python/Erlang編程語言對比分析及示例
情況 png 解耦 多態 有一種 blog fib 對比 基準 本文主要是介紹Go,從語言對比分析的角度切入。之所以選擇與Python、Erlang對比,是因為做為高級語言,它們語言特性上有較大的相似性,不過最主要的原因是這幾個我比較熟悉。 Go的很多語言特性借鑒與它的三個
常用6種type的form表單的input標簽分析及示例
分別是 密碼 question 分析 com bec 示例 nsa put <input> 標簽用於搜集用戶信息。 根據不同的 type 屬性值,輸入字段擁有很多種形式。輸入字段可以是文本字段、復選框、掩碼後的文本控件、單選按鈕、按鈕等等。 在這裏博主介紹6中t
用TensorFlow基於神經網路實現井字棋(含程式碼)
為了展示如何應用神經網路演算法模型,我們將使用神經網路來學習優化井字棋(Tic Tac Toe)。明確井字棋是一種決策性遊戲,並且走棋步驟優化是確定的。 開始 為了訓練神經網路模型,我們有一系列優化的不同的走棋棋譜,棋譜基於棋盤位置列表和對應的最佳落子點。考慮到棋盤的對稱性,通
常用6種type的form表單的input標籤分析及示例
<input> 標籤用於蒐集使用者資訊。 根據不同的 type 屬性值,輸入欄位擁有很多種形式。輸入欄位可以是文字欄位、複選框、掩碼後的文字控制元件、單選按鈕、按鈕等等。 在這裡博主介紹6中type的input,分別是文字域、密碼欄位、單選按鈕、複選按鈕、提交按鈕以及指定圖片按鈕 1:文字域 文
基於 Hessian 輕量級遠端呼叫的原理及示例
1 簡介 Hessian 是 Caucho 公司開發的一種基於二進位制 RPC 協議(Remote Procedure Call protocol)的輕量級遠端呼叫框架,其使用簡單的方法提供了 RMI 的功能。 相比 WebService,Hessian
UIScrollView的自動佈局最簡單實現方式,不用一句程式碼即可滾動
首先建立一個故事板,名字隨意,我取名叫Scroll.storyboard. 在右下角系統的元件庫中拖入一個viewcontroller,並設定為初始載入檢視控制器。具體為 然後在viewcontroller裡拖入一個scoll view,拖動scorllview的上下左右
結構體中指標賦值問題的分析及C程式碼示例
問題描述 某結構體的定義如下: typedef struct { int iAge; // 年齡 char szAddr1[100]; // 地址1 char *psz
python學習之網站的編寫(HTML,CSS,JS)(三)----------input系列的標籤詳解及示例程式碼(可上傳到伺服器form標籤)
文章編排,我們首先來講一下input系列的各種內容,然後用一個示例程式碼來清晰的理解其中特定的含義 input系列: 1.輸入文字內容: <input type="text" name="user"/>起個名字易於在伺服器端進行處理 2.輸入密碼內容:
Es6中的promise解決callback hell回撥地獄問題及示例程式碼
1.js中多個非同步呼叫(介面,讀取檔案)時沒有順序,若業務現在要求有順序的呼叫,就只能巢狀回撥,如果巢狀回撥3個以下程式碼量還不是很多,還可以湊乎,超過3個後重復程式碼多,可維護性差,程式碼醜陋ugly,就造成了callback hell,所以Es6出了promise解決此問題,jquery支援p
如何做出優雅的過渡效果? Dotween外掛的簡單介紹及示例程式碼
unity裡面做插值動畫的外掛有許多,比較常見的有itween、hotween、dotween。根據大家的反饋和實際體驗來說,dotween外掛在靈活性、穩定性、易用性上都十分突出。這裡簡單介紹下它的用法,並在後文做了一些效果示例,還是不錯的。 所謂”插值動畫“,顧名思義就是在兩個值中插入其他的