日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

网络编程中BIO和NIO的区别

發(fā)布時(shí)間:2024/9/30 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 网络编程中BIO和NIO的区别 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

網(wǎng)絡(luò)編程中BIO和NIO的區(qū)別

先上結(jié)論

BIO中,每個(gè)請(qǐng)求因?yàn)橐枞钡浇Y(jié)果返回,所以比較好的解決是每個(gè)請(qǐng)求都需要一個(gè)線程來(lái)處理,但是線程又是他的制約條件。

NIO中,每個(gè)請(qǐng)求進(jìn)來(lái)都會(huì)綁定到一個(gè)channel上,然后channel注冊(cè)給一個(gè) selector(多路選擇器),多路選擇器可以在channel有消息的時(shí)候進(jìn)行處理。
保證了只有selector在輪詢查找。最開始的 selector 使用的是 select方法,jdk使用了優(yōu)化后的epoll,避免了select有數(shù)量限制(1024/2048),在感興趣的channel上看是否有該類型數(shù)據(jù)出現(xiàn),如果有,則調(diào)用處理,沒有則繼續(xù)睡眠,等待喚醒。

selector 使用reactor模式,將事件監(jiān)聽分離(讀就緒/寫就緒/鏈接就緒),對(duì)每個(gè)事件都可以進(jìn)行獨(dú)立的操作。

reactor模式其實(shí)就是:注冊(cè)所有感興趣的事件處理器,單線程輪詢選擇就緒事件,執(zhí)行事件處理器。注冊(cè)監(jiān)聽(每個(gè)請(qǐng)求來(lái)都做) + 輪詢選擇(單線程處理) + 事件處理。

BIO

缺點(diǎn):每來(lái)一個(gè)請(qǐng)求就需要一個(gè)線程來(lái)處理,線程太多容易造成系統(tǒng)不可用.最開始的Tomcat使用的就是BIO
優(yōu)化:通過(guò)線程池來(lái)管理線程,但是造成新的缺點(diǎn):請(qǐng)求太多時(shí)不能被處理的請(qǐng)求就回阻塞,等待。不能被處理。正因?yàn)橄拗屏司€程數(shù)量,如果發(fā)生大量并發(fā)請(qǐng)求,超過(guò)最大數(shù)量的線程就只能等待,直到線程池中的有空閑的線程可以被復(fù)用。而對(duì)Socket的輸入流就行讀取時(shí),會(huì)一直阻塞。

服務(wù)端代碼

package order.core.common;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.util.concurrent.ThreadPoolExecutor;import javax.sound.sampled.Line;public class BIOServer {private static final int PORT = 8000;public static void main(String[] args) throws IOException {ServerSocket serverSocket = null;Socket socket = null;ThreadPoolExecutor threadPoolExecutor = null;try {serverSocket = new ServerSocket(PORT);System.out.println("serverSocket 啟動(dòng)了...");while (true) {socket = serverSocket.accept();System.out.println("接受到socket...");new Thread(new MyThread(socket)).start();}} catch (Exception e) {// TODO: handle exception} finally {socket.close();serverSocket.close();}} }class MyThread implements Runnable {private Socket socket;public MyThread(Socket socket) {this.socket = socket;}@Overridepublic void run() {BufferedReader in = null;PrintWriter out = null;try {in = new BufferedReader(new InputStreamReader(socket.getInputStream()));out = new PrintWriter(socket.getOutputStream(), true);String expression;String result;// 通過(guò)BufferedReader讀取一行// 如果已經(jīng)讀到輸入流尾部,返回null,退出循環(huán)// 如果得到非空值,就嘗試計(jì)算結(jié)果并返回if ((expression = in.readLine()) != null) {System.out.println("服務(wù)器收到消息:" + expression);out.print(5678978);}System.out.println("=========");} catch (Exception e) {e.printStackTrace();} finally {// 一些必要的清理工作if (in != null) {try {in.close();} catch (IOException e) {e.printStackTrace();}in = null;}if (out != null) {out.close();out = null;}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}socket = null;}}}}

客戶端代碼

package order.core.common;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket;public class BIOClient {private static final String IP = "127.0.0.1";// 默認(rèn)的端口號(hào)private static int DEFAULT_SERVER_PORT = 8000;private static String DEFAULT_SERVER_IP = "127.0.0.1";public static void send(String expression) {send(DEFAULT_SERVER_PORT, expression);}public static void main(String[] args) {send("12345");}public static void send(int port, String expression) {System.out.println("發(fā)送消息為:" + expression);Socket socket = null;BufferedReader in = null;PrintWriter out = null;try {socket = new Socket(DEFAULT_SERVER_IP, port);in = new BufferedReader(new InputStreamReader(socket.getInputStream()));out = new PrintWriter(socket.getOutputStream(), true);out.println(expression);System.out.println("___結(jié)果為:" + in.readLine());} catch (Exception e) {e.printStackTrace();} finally {// 一下必要的清理工作if (in != null) {try {in.close();} catch (IOException e) {e.printStackTrace();}in = null;}if (out != null) {out.close();out = null;}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}socket = null;}}} }

NIO

優(yōu)點(diǎn):只需要打開Selector和 ServerSocketChannel 并開啟非阻塞模式。然后只需要將ServerSocketChannel注冊(cè)給selector即可。Tomcat后續(xù)默認(rèn)全部使用NIO

監(jiān)聽的selector有四種:

public static final int OP_READ = 1 << 0;public static final int OP_WRITE = 1 << 2;public static final int OP_CONNECT = 1 << 3;public static final int OP_ACCEPT = 1 << 4;

服務(wù)端監(jiān)聽的是OP_ACCEPT。

客戶端監(jiān)聽的是OP_CONNECT。

發(fā)送消息類的監(jiān)聽OP_READ。

2.1、簡(jiǎn)介

NIO我們一般認(rèn)為是New I/O(也是官方的叫法),因?yàn)樗窍鄬?duì)于老的I/O類庫(kù)新增的(其實(shí)在JDK 1.4中就已經(jīng)被引入了,但這個(gè)名詞還會(huì)繼續(xù)用很久,即使它們?cè)诂F(xiàn)在看來(lái)已經(jīng)是“舊”的了,所以也提示我們?cè)诿麜r(shí),需要好好考慮),做了很大的改變。但民間跟多人稱之為Non-block I/O,即非阻塞I/O,因?yàn)檫@樣叫,更能體現(xiàn)它的特點(diǎn)。而下文中的NIO,不是指整個(gè)新的I/O庫(kù),而是非阻塞I/O。

NIO提供了與傳統(tǒng)BIO模型中的Socket和ServerSocket相對(duì)應(yīng)的SocketChannel和ServerSocketChannel兩種不同的套接字通道實(shí)現(xiàn)。

新增的著兩種通道都支持阻塞和非阻塞兩種模式。

阻塞模式使用就像傳統(tǒng)中的支持一樣,比較簡(jiǎn)單,但是性能和可靠性都不好;非阻塞模式正好與之相反。

對(duì)于低負(fù)載、低并發(fā)的應(yīng)用程序,可以使用同步阻塞I/O來(lái)提升開發(fā)速率和更好的維護(hù)性;對(duì)于高負(fù)載、高并發(fā)的(網(wǎng)絡(luò))應(yīng)用,應(yīng)使用NIO的非阻塞模式來(lái)開發(fā)。

下面會(huì)先對(duì)基礎(chǔ)知識(shí)進(jìn)行介紹。

2.2、緩沖區(qū) Buffer

Buffer是一個(gè)對(duì)象,包含一些要寫入或者讀出的數(shù)據(jù)。

在NIO庫(kù)中,所有數(shù)據(jù)都是用緩沖區(qū)處理的。在讀取數(shù)據(jù)時(shí),它是直接讀到緩沖區(qū)中的;在寫入數(shù)據(jù)時(shí),也是寫入到緩沖區(qū)中。任何時(shí)候訪問(wèn)NIO中的數(shù)據(jù),都是通過(guò)緩沖區(qū)進(jìn)行操作。

緩沖區(qū)實(shí)際上是一個(gè)數(shù)組,并提供了對(duì)數(shù)據(jù)結(jié)構(gòu)化訪問(wèn)以及維護(hù)讀寫位置等信息。

具體的緩存區(qū)有這些:ByteBuffe、CharBuffer、 ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。他們實(shí)現(xiàn)了相同的接口:Buffer。

2.3、通道 Channel

我們對(duì)數(shù)據(jù)的讀取和寫入要通過(guò)Channel,它就像水管一樣,是一個(gè)通道。通道不同于流的地方就是通道是雙向的,可以用于讀、寫和同時(shí)讀寫操作。

底層的操作系統(tǒng)的通道一般都是全雙工的,所以全雙工的Channel比流能更好的映射底層操作系統(tǒng)的API。

Channel主要分兩大類:

SelectableChannel:用戶網(wǎng)絡(luò)讀寫 FileChannel:用于文件操作
后面代碼會(huì)涉及的ServerSocketChannel和SocketChannel都是SelectableChannel的子類。

2.4、多路復(fù)用器 Selector

Selector是Java NIO 編程的基礎(chǔ)。

Selector提供選擇已經(jīng)就緒的任務(wù)的能力:Selector會(huì)不斷輪詢注冊(cè)在其上的Channel,如果某個(gè)Channel上面發(fā)生讀或者寫事件,這個(gè)Channel就處于就緒狀態(tài),會(huì)被Selector輪詢出來(lái),然后通過(guò)SelectionKey可以獲取就緒Channel的集合,進(jìn)行后續(xù)的I/O操作。

一個(gè)Selector可以同時(shí)輪詢多個(gè)Channel,因?yàn)镴DK使用了epoll()代替?zhèn)鹘y(tǒng)的select實(shí)現(xiàn),所以沒有最大連接句柄1024/2048的限制。所以,只需要一個(gè)線程負(fù)責(zé)Selector的輪詢,就可以接入成千上萬(wàn)的客戶端。

服務(wù)端代碼

package order.core.common;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 Server {private static int DEFAULT_PORT = 8001;private static ServerHandle serverHandle;public static void start() {start(DEFAULT_PORT);}public static synchronized void start(int port) {if (serverHandle != null)serverHandle.stop();serverHandle = new ServerHandle(port);new Thread(serverHandle, "Server").start();}public static void main(String[] args) {start();} }class ServerHandle implements Runnable {private Selector selector;private ServerSocketChannel serverChannel;private volatile boolean started;/*** 構(gòu)造方法* * @param port* 指定要監(jiān)聽的端口號(hào)*/public ServerHandle(int port) {try {// 創(chuàng)建選擇器selector = Selector.open();// 打開監(jiān)聽通道serverChannel = ServerSocketChannel.open();// 如果為 true,則此通道將被置于阻塞模式;如果為 false,則此通道將被置于非阻塞模式serverChannel.configureBlocking(false);// 開啟非阻塞模式// 綁定端口 backlog設(shè)為1024serverChannel.bind(new InetSocketAddress("localhost",port));// 監(jiān)聽客戶端連接請(qǐng)求serverChannel.register(selector, SelectionKey.OP_ACCEPT);// 標(biāo)記服務(wù)器已開啟started = true;System.out.println("服務(wù)器已啟動(dòng),端口號(hào):" + port);} catch (IOException e) {e.printStackTrace();System.exit(1);}}public void stop() {started = false;}@Overridepublic void run() {// 循環(huán)遍歷selectorwhile (started) {try {// 無(wú)論是否有讀寫事件發(fā)生,selector每隔1s被喚醒一次selector.select(1000);// 阻塞,只有當(dāng)至少一個(gè)注冊(cè)的事件發(fā)生的時(shí)候才會(huì)繼續(xù).// selector.select();Set<SelectionKey> keys = selector.selectedKeys();Iterator<SelectionKey> it = keys.iterator();SelectionKey key = null;while (it.hasNext()) {key = it.next();it.remove();try {handleInput(key);} catch (Exception e) {if (key != null) {key.cancel();if (key.channel() != null) {key.channel().close();}}}}} catch (Throwable t) {t.printStackTrace();}}// selector關(guān)閉后會(huì)自動(dòng)釋放里面管理的資源if (selector != null)try {selector.close();} catch (Exception e) {e.printStackTrace();}}private void handleInput(SelectionKey key) throws IOException {if (key.isValid()) {// 處理新接入的請(qǐng)求消息if (key.isAcceptable()) {ServerSocketChannel ssc = (ServerSocketChannel) key.channel();// 通過(guò)ServerSocketChannel的accept創(chuàng)建SocketChannel實(shí)例// 完成該操作意味著完成TCP三次握手,TCP物理鏈路正式建立SocketChannel sc = ssc.accept();// 設(shè)置為非阻塞的sc.configureBlocking(false);// 注冊(cè)為讀sc.register(selector, SelectionKey.OP_READ);}// 讀消息if (key.isReadable()) {SocketChannel sc = (SocketChannel) key.channel();// 創(chuàng)建ByteBuffer,并開辟一個(gè)1M的緩沖區(qū)ByteBuffer buffer = ByteBuffer.allocate(1024);// 讀取請(qǐng)求碼流,返回讀取到的字節(jié)數(shù)int readBytes = sc.read(buffer);// 讀取到字節(jié),對(duì)字節(jié)進(jìn)行編解碼if (readBytes > 0) {// 將緩沖區(qū)當(dāng)前的limit設(shè)置為position=0,用于后續(xù)對(duì)緩沖區(qū)的讀取操作buffer.flip();// 根據(jù)緩沖區(qū)可讀字節(jié)數(shù)創(chuàng)建字節(jié)數(shù)組byte[] bytes = new byte[buffer.remaining()];// 將緩沖區(qū)可讀字節(jié)數(shù)組復(fù)制到新建的數(shù)組中buffer.get(bytes);String expression = new String(bytes, "UTF-8");System.out.println("服務(wù)器收到消息:" + expression);// 處理數(shù)據(jù)String result = null;try {result = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa";} catch (Exception e) {result = "計(jì)算錯(cuò)誤:" + e.getMessage();}// 發(fā)送應(yīng)答消息doWrite(sc, result);}// 沒有讀取到字節(jié) 忽略// else if(readBytes==0);// 鏈路已經(jīng)關(guān)閉,釋放資源else if (readBytes < 0) {key.cancel();sc.close();}}}}// 異步發(fā)送應(yīng)答消息private void doWrite(SocketChannel channel, String response) throws IOException {// 將消息編碼為字節(jié)數(shù)組byte[] bytes = response.getBytes();// 根據(jù)數(shù)組容量創(chuàng)建ByteBufferByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);// 將字節(jié)數(shù)組復(fù)制到緩沖區(qū)writeBuffer.put(bytes);// flip操作writeBuffer.flip();// 發(fā)送緩沖區(qū)的字節(jié)數(shù)組channel.write(writeBuffer);// ****此處不含處理“寫半包”的代碼} }

客戶端代碼

package order.core.common; 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;public class Client {private static String DEFAULT_HOST = "127.0.0.1";private static int DEFAULT_PORT = 8001;private static ClientHandler clientHandle;public static void start(){start(DEFAULT_HOST,DEFAULT_PORT);}public static synchronized void start(String ip,int port){if(clientHandle!=null)clientHandle.stop();clientHandle = new ClientHandler(ip,port);new Thread(clientHandle,"Server").start();}//向服務(wù)器發(fā)送消息public static boolean sendMsg(String msg) throws Exception{clientHandle.sendMsg(msg);return true;}public static void main(String[] args) throws Exception{start();sendMsg("aaaaaaaaa");} }class ClientHandler implements Runnable{private String host;private int port;private Selector selector;private static SocketChannel socketChannel;private static volatile boolean started;public ClientHandler(String ip,int port) {this.host = ip;this.port = port;try{//創(chuàng)建選擇器selector = Selector.open();//打開監(jiān)聽通道socketChannel = SocketChannel.open();//如果為 true,則此通道將被置于阻塞模式;如果為 false,則此通道將被置于非阻塞模式socketChannel.configureBlocking(false);//開啟非阻塞模式socketChannel.connect(new InetSocketAddress("127.0.0.1", port));System.out.println(socketChannel.finishConnect());socketChannel.register(selector, SelectionKey.OP_CONNECT);started = true;}catch(IOException e){e.printStackTrace();System.exit(1);}}public void stop(){started = false;}@Overridepublic void run() {//循環(huán)遍歷selectorwhile(started){try{//無(wú)論是否有讀寫事件發(fā)生,selector每隔1s被喚醒一次selector.select(1000);//阻塞,只有當(dāng)至少一個(gè)注冊(cè)的事件發(fā)生的時(shí)候才會(huì)繼續(xù). // selector.select();Set<SelectionKey> keys = selector.selectedKeys();Iterator<SelectionKey> it = keys.iterator();SelectionKey key = null;while(it.hasNext()){key = it.next();it.remove();try{handleInput(key);}catch(Exception e){if(key != null){key.cancel();if(key.channel() != null){key.channel().close();}}}}}catch(Exception e){e.printStackTrace();System.exit(1);}}}private void handleInput(SelectionKey key) throws IOException{if(key.isValid()){SocketChannel sc = (SocketChannel) key.channel();if(key.isConnectable()){if(sc.finishConnect());else System.exit(1);}//讀消息if(key.isReadable()){//創(chuàng)建ByteBuffer,并開辟一個(gè)1M的緩沖區(qū)ByteBuffer buffer = ByteBuffer.allocate(1024);//讀取請(qǐng)求碼流,返回讀取到的字節(jié)數(shù)int readBytes = sc.read(buffer);//讀取到字節(jié),對(duì)字節(jié)進(jìn)行編解碼if(readBytes>0){//將緩沖區(qū)當(dāng)前的limit設(shè)置為position=0,用于后續(xù)對(duì)緩沖區(qū)的讀取操作buffer.flip();//根據(jù)緩沖區(qū)可讀字節(jié)數(shù)創(chuàng)建字節(jié)數(shù)組byte[] bytes = new byte[buffer.remaining()];//將緩沖區(qū)可讀字節(jié)數(shù)組復(fù)制到新建的數(shù)組中buffer.get(bytes);String result = new String(bytes,"UTF-8");System.out.println("客戶端收到消息:" + result);}//沒有讀取到字節(jié) 忽略 // else if(readBytes==0);//鏈路已經(jīng)關(guān)閉,釋放資源else if(readBytes<0){key.cancel();sc.close();}}}}//異步發(fā)送消息private void doWrite(SocketChannel channel,String request) throws IOException{//將消息編碼為字節(jié)數(shù)組byte[] bytes = request.getBytes();//根據(jù)數(shù)組容量創(chuàng)建ByteBufferByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);//將字節(jié)數(shù)組復(fù)制到緩沖區(qū)writeBuffer.put(bytes);//flip操作writeBuffer.flip();//發(fā)送緩沖區(qū)的字節(jié)數(shù)組channel.write(writeBuffer);//****此處不含處理“寫半包”的代碼}public void doConnect() throws IOException{System.out.println("==");try {System.out.println(socketChannel.isOpen());System.out.println(socketChannel.isConnected());} catch (Exception e) {// TODO: handle exception}}public void sendMsg(String msg) throws Exception{socketChannel.register(selector, SelectionKey.OP_READ);doWrite(socketChannel, msg);} }

總結(jié)

以上是生活随笔為你收集整理的网络编程中BIO和NIO的区别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 午夜羞羞影院 | 欧美日韩精品一区二区在线播放 | 美女隐私直播 | 香蕉久草 | 污片免费在线观看 | 色999五月色 | 国产成人精品视频ⅴa片软件竹菊 | 成年人免费网站视频 | 精品一区二区久久 | 色二区 | 乌克兰做爰xxxⅹ性视频 | 欧美一区免费看 | 超碰888 | 欧美精品综合 | 久久橹 | 欧美老熟妇喷水 | 国产美女黄网站 | 亚洲自拍偷拍色图 | 波多野结衣高清电影 | 小视频在线播放 | 久久香焦 | 精品人妻一区二区三区日产 | 国产乱码精品 | 一本av在线 | 一本大道久久久久精品嫩草 | 久久国产精品毛片 | 久久盗摄 | 日本高清黄色电影 | 资源av| 碧蓝之海动漫在线观看免费高清 | 国产成人久久婷婷精品流白浆 | 伊人久久精品一区二区三区 | 国产稀缺精品盗摄盗拍 | 国产午夜精品无码一区二区 | 欧美日韩国产一区 | 国产高清精品软件丝瓜软件 | 97青草 | 亚洲一区二区久久 | 免费中文字幕日韩 | 天天综合国产 | 一本久久精品一区二区 | 亚洲 成人 av | 国产91视频在线观看 | 黄色片美女 | 国产高清视频免费观看 | 国产清纯白嫩初高中在线观看性色 | 国产精品久久久午夜夜伦鲁鲁 | 2019天天干天天操 | 精品免费一区二区三区 | 美女啪啪无遮挡 | 少妇一晚三次一区二区三区 | 无码人妻一区二区三区精品视频 | 蜜臀视频一区二区 | 中文字幕久久综合 | 日韩激情视频 | 中文字幕在线国产 | 精品人妻少妇AV无码专区 | www精品一区二区三区 | www.rihan | 国产一级片一区二区 | 99久久久无码国产精品性青椒 | 久久久成人网 | 国产在线一区二区视频 | 日本黄色网页 | 国产做爰xxxⅹ性视频国 | 日日夜夜婷婷 | 91中文字幕在线播放 | 日韩av免费网址 | 孕妇爱爱视频 | 女人的洗澡毛片毛多 | a∨色狠狠一区二区三区 | 国产免费高清视频 | 日日爱666 | 日韩视频在线一区二区 | 91插插插插插插插 | 欧美激情一区二区 | 国产精品人 | 五月婷婷爱爱 | 黄色网页在线免费观看 | 国产成人99久久亚洲综合精品 | 午夜精品久久久久久久无码 | 久久精品欧美一区二区 | 农村寡妇一区二区三区 | 日本午夜网站 | 国产精品电影一区二区 | 日韩一级片网址 | 亚洲天堂三级 | 伊人久久激情 | 影音先锋亚洲成aⅴ人在 | 日本精品免费在线观看 | 亚洲砖区区免费 | 毛片av免费看 | 日本a级免费 | 潘金莲一级淫片a.aaaaa播放 | 国产乱人对白 | 四虎av| 黄色一级免费 | 日韩欧美国产一区二区 | 浪荡奴双性跪着伺候 |