epoll nio區別_【總結】兩種 NIO 實現:Selector 與 Epoll

我想用這個話題小結下最近這一階段的各種測試和開發。其實文章的內容主要還是想總結一下

NIO Socket

,以及兩種不同操作系統實現

NIO

的方式,

selector

epoll

問題應該從服務器端開始說起。我們都寫過net包下的socket,用socket的accept方法來等待客戶端的請求,請求來了則處理,沒有則一直等待,然后反復循環。這樣的方式,類似于重用進程,要說線程也可以,始終就在這一條路上堵著。這樣沒有并發可言,我們想到了可以用多線程,用線程池的方式來解決這個問題。這樣一般的小問題能解決了,100個初始化的線程,解決幾千個連接應該沒什么問題。可是,如果我做的是傳輸的項目呢,這100個線程還是阻塞的,第101個線程連接的時候,如果前面的100個都還在傳輸,那這第101個人還是在空等,而且他連個回音都不能收到。而且這樣的方式實現起來并不怎么容易,雖然線程池有Exectors這樣的類幫你生成,可是遇到共享變量和協同等問題還是很頭疼。一個更好的做法是,模仿FTP一樣,將指令與傳輸分開進行,一個端口負責簡短的指令,盡可能的端連接,而其他端口處理業務。這樣至少服務器能返回消息了。

第三種解決方案,多數情況下,也是最快的一種被提出來了,選擇器selector。用一個線程來查詢一組socket,找出已經準備好讀寫的,然后按順序處理socket,當然這種實現方式的前提是IO必須使用通道和緩沖區而不是流。

用java來開發NIO socket的程序,最先要理解的還是各種概念。

通道channel,在NIO socket中使用到的通道有三個,SocketChannel、ServerSocketChannel、DatagramChannel。前兩種基于TCP,最后一種一種用來實現UDP的通信。ServerSocketChannel不做任何數據上的處理,只是提供通道,負責連接。SocketChannel職責和net包下的socket類似,只不過這里是以通道的形勢來對接。

緩沖區Buffer,這里最常用的還是ByteBuffer,在mina中使用的IoBuffer也是基于ByteBuffer實現的。它的好處是可以自己拼裝去想到的數據。當然利用通道后數據切換的速度也會更快了。

要實現非阻塞IO最重要的還是選擇器:

Selector

The Selector class manages information about a set of registered channels and their readiness states. Channels are registered with selectors, and a selector can be asked to update the readiness states of the channels currently registered with it. When doing so, the invoking thread can optionally indicate that it would prefer to be suspended until one of the registered channels is ready.

SelectableChannel

This abstract class provides the common methods needed to implement channel selectability. It's the superclass of all channel classes that support readiness selection. FileChannel objects are not selectable because they don't extend from SelectableChannel. All the socket channel classes are selectable, as well as the channels obtained from a Pipe object. SelectableChannel objects can be registered with Selector objects, along with an indication of which operations on that channel are of interest for that selector. A channel can be registered with multiple selectors, but only once per selector.

SelectionKey

A SelectionKey encapsulates the registration relationship between a specific channel and a specific selector. A SelectionKey object is returned from SelectableChannel.register( ) and serves as a token representing the registration. SelectionKey objects contain two bit sets (encoded as integers) indicating which channel operations the registrant has an interest in and which operations the channel is ready to perform.

Selector

管理被注冊的通道的集合的信息和其就緒狀態,同時也更新通道的就緒狀態。并且一個通道可以被注冊到多個選擇器上,而對于同一個選擇器則只能被注冊一次。

import java.io.IOException;

import java.net.InetSocketAddress;

import java.net.ServerSocket;

import java.nio.ByteBuffer;

import java.nio.channels.SelectableChannel;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.ServerSocketChannel;

import java.nio.channels.SocketChannel;

import java.util.Iterator;

public class SelectSockets {

private static final int PORT = 8082;

private ByteBuffer buffer = ByteBuffer.allocate(1024);

public static void main(String[] args) throws IOException {

SelectSockets ss = new SelectSockets();

ss.go();

}

public void go() throws IOException {

System.out.println("listening on port:" + PORT);

ServerSocketChannel ssc = ServerSocketChannel.open();

ServerSocket ss = ssc.socket();

Selector selector = Selector.open();

ss.bind(new InetSocketAddress(PORT));

ssc.configureBlocking(false);

ssc.register(selector, SelectionKey.OP_ACCEPT);

while (true) {

int n = selector.select();

if (n == 0) {

continue;

}

Iterator iter = selector.selectedKeys().iterator();

while (iter.hasNext()) {

SelectionKey key = iter.next();

if (key.isAcceptable()) {

ServerSocketChannel server = (ServerSocketChannel) key

.channel();

SocketChannel client = server.accept();

register(selector, client, SelectionKey.OP_READ);

System.out.println("Accept client:" + client);

acceptClient(client);

}

if (key.isReadable()) {

readData(key);

}

iter.remove();

}

}

}

protected void register(Selector selector, SelectableChannel channel,

int ops) throws IOException {

if (channel == null) {

return;

}

channel.configureBlocking(false);

channel.register(selector, ops);

}

protected void readData(SelectionKey key) throws IOException {

SocketChannel socketChannel = (SocketChannel) key.channel();

int count;

while ((count = socketChannel.read(buffer)) > 0) {

buffer.flip();

while (buffer.hasRemaining()) {

socketChannel.write(buffer);

}

buffer.clear();

if (count < 0) {

socketChannel.close();

}

}

}

private void acceptClient(SocketChannel channel) throws IOException {

buffer.clear();

buffer.put("you have already connected server!".getBytes());

buffer.flip();

channel.write(buffer);

}

}

上面的代碼就是一般的

NIO

服務器端實現的過程。

當然對于一個企業級的應用這樣的代碼肯定是太單薄了,僅僅就

selector

而言,

我們是不是能共通過用多線程的方式來增強他的處理能力?是不是只有一個線程在跑

selector

,讓這一個線程處理那么多的連接有點兒過意不去。答案并不是和你想的一樣

For the first scenario, in which you want to bring more threads into play to service channels,

resist the urge to use multiple selectors

. Performing readiness selection on large numbers of channels is not expensive;

most of the work is done by the underlying operating system

. Maintaining multiple selectors and randomly assigning channels to one of them is not a satisfactory solution to this problem. It simply makes smaller versions of the same scenario.

如果您想要將更多的線程來為通道提供服務,請抵抗住使用多個選擇器的欲望。在大量通道上執行就緒選擇并不會有很大的開銷,大多數工作是由底層操作系統完成的。管理多個選擇器并隨機地將通道分派給它們當中的一個并不是這個問題的合理的解決方案。這只會形成這個場景的一個更小的版本。

一個更好的方案就是,讓一個線程處理selector,讓其他線程去處理就緒通道的業務。

模式就和上圖上描述的一樣,但是我的疑問來了,這樣和線程池下的服務端連接好像看起來并沒有多少大的優勢。同樣還是要啟那么多的線程去處理這些業務。這也是我最近一直想從

mina

源碼中找到的答案,可是還是沒有發現我想要的,它也是通過

IoSession

用原型模型的方式來實現并發的。不過我估計

Mina

應該是有異步的實現,這樣也會對性能上有影響。具體還有待研究。

最后要說的就是客戶端了,最近其實也的客戶端比較多,版本一個接一個,寫了不下七八個,各種方式,各種測試,其實有幾點心得可以分享:

l? 如果是做大文件的傳輸,切分的性價比其實比連續傳的性價比高不了多少,雖然像迅雷這樣可以分好多塊傳輸,但那畢竟是

P2P

的結構,文件本來就松散的。考慮到切分再校驗再重組,這樣還不如切大塊,然后順序傳。

l? 盡量將指令和傳輸分開,指令可以加密,然后更具協議,返回端口和地址讓服務器端做到分布式的處理。

l? 還有就是客戶端是否要用非阻塞模式,客戶端如果不是做出

P2P

模式的,而且能用多線程解決問題的,就沒必要用非阻塞的模式,因為非阻塞模式的發送和接收的時機很難控制,特別是用原生的

NIO

寫的

socket

l? 在做兩端通信的時候,特別是不同語言寫的程序和不同操作系統下,要注意字節序(高有效和低有效)和進制的問題。

l

Mina

這樣的框架很好,如果再配上

protobuf

這樣的多平臺序列化工具,可以很好的實現自定義協議的通信。自己訂協議的好處就是安全,而且能做應答機制。

Epoll是Linux下多路復用IO接口select/poll的增強版本,它能顯著提高程序在大量并發連接中只有少量活躍的情況下的系統CPU利用率,因為它會復用文件描述符集合來傳遞結果而不用迫使開發者每次等待事件之前都必須重新準備要被偵聽的文件描述符集合,另一點原因就是獲取事件的時候,它無須遍歷整個被偵聽的描述符集,只要遍歷那些被內核IO事件異步喚醒而加入Ready隊列的描述符集合就行了。epoll除了提供select/poll那種IO事件的電平觸發(Level Triggered)外,還提供了邊沿觸發(Edge Triggered),這就使得用戶空間程序有可能緩存IO狀態,減少epoll_wait/epoll_pwait的調用,提高應用程序效率。

在linux下,NIO可以采用epoll來實現非阻塞,注意,是在linux下:

-Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.EPollSelectorProvider

--------------------------------------------------------------------

下周就要開始弄kafka了,其實網絡方面的測試還沒有找到最好的解決方案,雖然測了很多東西,但是真的是沒有時間去做更多更復雜的東西。接下來趕緊把mina的源碼看完,再看看netty就要把重心放在kafka上了。其實網絡編程還是很有必要的,好多分布式的通信方案都可以建立在一套比較完整的消息機制上。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/370769.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/370769.shtml
英文地址,請注明出處:http://en.pswp.cn/news/370769.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MapReduce的工作原理

一、MapReduce模型框架 MapReduce是一個用于大規模數據處理的分布式計算模型&#xff0c;最初由Google工程師設計并實現的&#xff0c;Google已經將完整的MapReduce論文公開發布了。其中的定義是&#xff0c;MapReduce是一個編程模型&#xff0c;是一個用于處理和生成大規模數據…

react實現多行文本超出加省略號

http://www.css88.com/archives/5206 overflow : hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; 根據該文章方法&#xff0c;放在react項目中發現并不能實現&#xff0c;仔細觀察發現原來react解析出來的css樣…

Google Guava MultiMaps

番石榴 這是系列文章中的第一篇&#xff0c;我將嘗試解釋和探索Google很棒的Guava java庫 。 我在搜索Apache Commons Collections的通用版本時遇到了番石榴&#xff08;Guava&#xff09;–我需要一個Bimap并且厭倦了必須使用強制類型轉換來填充我的代碼–但是我發現要好得多…

qq群 html,我的群組-普通群組.html

&#xfeff;我的群組&#xff0d;普通群組$axure.utils.getTransparentGifPath function() { return resources/images/transparent.gif; };$axure.utils.getOtherPath function() { return resources/Other.html; };$axure.utils.getReloadPath function() { return resou…

查看PLC IP 端口_西門子828D數控系統X130接口通訊怪異現象(X130手動設置的 IP)...

西門子828D數控系統&#xff0c;調試PLC過程中遇到網絡通信怪異問題(不能直連非要加個路由器)&#xff0c;筆記本電腦的以太網網絡直接連接顯示網絡電纜被拔出&#xff0c;如下圖所示&#xff1a;奇怪&#xff0c;怎么出現這種情況了呢&#xff0c;因為我用這臺電腦調試過別的P…

基于嵌入式系統的gnash最小庫依賴關系

已經對gnash的依賴庫作了詳細的分析&#xff0c;下邊是必須依賴的庫&#xff1a;GIF Required libungif-devlibxml2 Required libxml2-devPNG Requir…

git 創建webpack項目_一次create-react-app創建項目升級webpack的流水賬

不再贅述為什么要升級webpack4&#xff0c;有興趣的小伙伴可以看一下 知乎&#xff1a;如何評價webpack4下面擼起袖子開干&#xff1a;克隆項目&#xff0c;新建分支git checkout -b feature_webpack_upgrade# 相當于以下兩句的簡寫git branch feature_webpack_upgradegit chec…

bzoj1263

貪心 n%31 分出一個4&#xff0c;其余用3&#xff0c;n%32&#xff0c;分出一個2&#xff0c;其余用3&#xff0c;然后高精度就行了 #include<bits/stdc.h> using namespace std; const int N 5005; struct BigInt {int len;int a[N];BigInt() { memset(a, 0, sizeof(a)…

c語言volatile_[技術]為什么單片機C語言編程時某一變量有時亂碼

最近一個項目里面&#xff0c;在KEIL中用C語言在單片機里面定義了一個狀態機全局變量&#xff0c;這個變量隨時會改變&#xff0c;用于切換觸摸屏的界面&#xff0c;可是程序運行中出現了一個問題&#xff0c;這個狀態機號總是出現了被莫名奇妙改變的問題&#xff0c;導致觸屏不…

沙箱Java代碼

在上一篇文章中&#xff0c;我們研究了如何保護移動Java代碼 。 這樣做的一種選擇是在籠子或沙箱中運行代碼。 這篇文章探討了如何為Java應用程序設置這樣的沙箱。 安全經理 Java中支持沙箱的安全性設施是java.lang.SecurityManager 。 默認情況下&#xff0c;Java在沒有Se…

微型計算機2017年9月上,2017年9月計算機一級考試WPS Office沖刺題

2017年9月計算機一級考試WPS Office沖刺題2017年下半年計算機一級考試將在9月份進行&#xff0c;為了方便考生備考計算機一級考試。下面是小編為大家帶來的計算機一級考試WPS Office沖刺題&#xff0c;歡迎閱讀。沖刺題一&#xff1a;1、PowerPoint 演示文稿和模板的擴展名是【…

七. 多線程編程5.創建多線程

到目前為止&#xff0c;我們僅用到兩個線程&#xff1a;主線程和一個子線程。然而&#xff0c;你的程序可以創建所需的更多線程。例如&#xff0c;下面的程序創建了三個子線程&#xff1a;// Create multiple threads.class NewThread implements Runnable { String name; /…

11尺寸長寬 iphone_弱電工程LED顯示屏尺寸規格及計算方法

前言&#xff1a;led屏幕在生活中&#xff0c;隨處可見&#xff0c;顯示屏、廣播屏等等&#xff0c;但是led尺寸怎么計算的&#xff0c;你知道嗎&#xff1f;今天我們一起了解一下led屏幕尺寸的計算方法。正文&#xff1a;一、點間距的計算1、各單元板常見型號及尺寸LED屏普遍是…

marquee標簽的使用

<!DOCTYPE html> <html> <head><meta charset"utf-8" /><title>演示marquee</title><style type"text/css">*{padding: 0px;margin: 0px;}marquee{border: 1px solid purple;}img{width: 360px;height: auto;}&…

32位數據源中沒有mysql_[SpringBoot實戰]快速配置多數據源(整合MyBatis)

前言由于業務需求&#xff0c;需要同時在SpringBoot中配置兩套數據源&#xff08;連接兩個數據庫&#xff09;&#xff0c;要求能做到service層在調用各數據庫表的mapper時能夠自動切換數據源&#xff0c;也就是mapper自動訪問正確的數據庫。本文內容&#xff1a;在SpringbootM…

考研計算機冷門學校,考研5個冷門的985院校 別隨大流,這些幾所也是很不錯的...

導語&#xff1a;想必大家考研的目的有很多&#xff0c;最主要的就是想去更好的學校提升自己&#xff0c;大部分會肯定是會更傾向于985這類的院校&#xff0c;每年其實除了那些被“擠破頭”的985院校&#xff0c;其實還有不少“低調”的985院校是非常值得報考的&#xff0c;下面…

名為 cursor_jinserted 的游標不存在_質量工程師必須了解的測量常識,你不知道怎么行...

01測量器具的分類測量器具是一種具有固定形態、用以復現或提供一個或多個已知量值的器具。按用途的不同量具可分為以下幾類&#xff1a;1. 單值量具只能體現一個單一量值的量具。可用來校對和調整其它測量器具或作為標準量與被測量直接進行比較&#xff0c;如量塊、角度量塊等。…

window.onload事件

!DOCTYPE html> <html> <head lang"en"><meta charset"UTF-8"><title>window.onload</title><!--window.onload注意點&#xff1a;01.在整個頁面中只能存在一次&#xff0c;否則后面會覆蓋前面02.頁面中所有的內容加載…

bzoj4869

http://www.lydsy.com/JudgeOnline/problem.php?id4869 終于A了。。。參考了下dalao的代碼。。。 拓展歐幾里得定理&#xff0c;改了幾次就不變了&#xff0c;但是用的時候要在快速冪里判是不是要用。 #include<bits/stdc.h> using namespace std; typedef long long ll…

一張圖一個表——CSS選擇器總結

CSS選擇器總結&#xff1a; (這些表是一張圖片^_^) 看底部 完整思維導圖圖片和表格的下載地址&#xff1a;https://download.csdn.net/download/denlnyyr/10597820 &#xff08;我不想選擇要積分幣下載的&#xff0c;但那里最低必須選擇1個積分……&#xff09; 參考文獻&…