中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java中怎么使用NIO實現網絡編程

發布時間:2021-07-02 14:54:23 來源:億速云 閱讀:235 作者:Leah 欄目:編程語言

本篇文章為大家展示了Java中怎么使用NIO實現網絡編程,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

為什么需要NIO

使用Java編寫過Socket程序的同學一定都知道Socket和SocketServer。當調用某個調用的時候,調用的地方就會阻塞,等待響應。這種方式對于小規模的程序非常方便,但是對于大型的程序就有點力不從心了,當有大量的連接的時候,我們可以為每一個連接建立一個線程來操作。但是這種做法帶來的缺陷也是顯而易見的:

  1. 硬件能夠支持大量的并發。

  2. 并發的數量始終有一個上限。

  3. 各個線程之間的優先級不好控制。

  4. 各個Client之間的交互與同步困難。

我們也可以使用一個線程來處理所有的請求,使用不阻塞的IO,輪詢查詢所有的Client。這種做法同樣也有缺陷:無法迅速響應Client端,同時會消耗大量輪詢查詢的時間。

所以,我們需要一種poll的模式來處理這種情況,從大量的網絡連接中找出來真正需要服務的Client。這正是NIO誕生的原因:提供一種Poll的模式,在所有的Client中找到需要服務的Client。

回到我們剛剛說到的3個最最重要的Class:java.nio.channels中Selector和Channel,以及java.nio中的Buffer。

Channel代表一個可以被用于Poll操作的對象(可以是文件流也可以使網絡流),Channel能夠被注冊到一個Selector中。通過調用Selector的select方法可以從所有的Channel中找到需要服務的實例(Accept,read ..)。

Buffer對象提供讀寫數據的緩存。相對于我們熟悉的Stream對象,Buffer提供更好的性能以及更好的編程透明性(人為控制緩存的大小以及具體的操作)。

配合BUFFER使用CHANNEL

與傳統模式的編程不用,Channel不使用Stream,而是Buffer。我們來實現一個簡單的非阻塞Echo Client:

package com.cnblogs.gpcuster;  import java.net.InetSocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel;  public class TCPEchoClientNonblocking { public static void main(String args[]) throws Exception { if ((args.length < 2) || (args.length > 3))// Testforcorrect#ofargs throw new IllegalArgumentException( "Parameter(s): <Server> <Word> [<Port>]"); String server = args[0];// ServernameorIPaddress // ConvertinputStringtobytesusingthedefaultcharset byte[] argument = args[1].getBytes(); int servPort = (args.length == 3) ? Integer.parseInt(args[2]) : 7; // Createchannelandsettononblocking SocketChannel clntChan = SocketChannel.open(); clntChan.configureBlocking(false); // Initiateconnectiontoserverandrepeatedlypolluntilcomplete if (!clntChan.connect(new InetSocketAddress(server, servPort))) { while (!clntChan.finishConnect()) { System.out.print(".");// Dosomethingelse } } ByteBuffer writeBuf = ByteBuffer.wrap(argument); ByteBuffer readBuf = ByteBuffer.allocate(argument.length); int totalBytesRcvd = 0;// Totalbytesreceivedsofar int bytesRcvd;// Bytesreceivedinlastread while (totalBytesRcvd < argument.length) { if (writeBuf.hasRemaining()) { clntChan.write(writeBuf); } if ((bytesRcvd = clntChan.read(readBuf)) == -1) { throw new SocketException("Connection closed prematurely"); } totalBytesRcvd += bytesRcvd; System.out.print(".");// Dosomethingelse } System.out.println("Received:" + // converttoStringperdefaultcharset new String(readBuf.array(), 0, totalBytesRcvd)); clntChan.close(); } }

這段代碼使用ByteBuffer來保存讀寫的數據。通過clntChan.configureBlocking(false); 設置后,其中的connect,read,write操作都不回阻塞,而是立刻放回結果。

使用SELECTOR

Selector的可以從所有的被注冊到自己Channel中找到需要服務的實例。

我們來實現Echo Server。

首先,定義一個接口:

package com.cnblogs.gpcuster;  import java.nio.channels.SelectionKey; import java.io.IOException;  public interface TCPProtocol { void handleAccept(SelectionKey key) throws IOException;  void handleRead(SelectionKey key) throws IOException;  void handleWrite(SelectionKey key) throws IOException; } 我們的Echo Server將使用這個接口。然后我們實現Echo Server: import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.util.Iterator;  public class TCPServerSelector { private static final int BUFSIZE = 256;// Buffersize(bytes) private static final int TIMEOUT = 3000;// Waittimeout(milliseconds)  public static void main(String[] args) throws IOException { if (args.length < 1) {// Testforcorrect#ofargs throw new IllegalArgumentException("Parameter(s):<Port>..."); } // Createaselectortomultiplexlisteningsocketsandconnections Selector selector = Selector.open(); // Createlisteningsocketchannelforeachportandregisterselector for (String arg : args) { ServerSocketChannel listnChannel = ServerSocketChannel.open(); listnChannel.socket().bind( new InetSocketAddress(Integer.parseInt(arg))); listnChannel.configureBlocking(false);// mustbenonblockingtoregister // Registerselectorwithchannel.Thereturnedkeyisignored listnChannel.register(selector, SelectionKey.OP_ACCEPT); } // Createahandlerthatwillimplementtheprotocol TCPProtocol protocol = new EchoSelectorProtocol(BUFSIZE); while (true) {// Runforever,processingavailableI/Ooperations // Waitforsomechanneltobeready(ortimeout) if (selector.select(TIMEOUT) == 0) {// returns#ofreadychans System.out.print("."); continue; } // GetiteratoronsetofkeyswithI/Otoprocess Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator(); while (keyIter.hasNext()) { SelectionKey key = keyIter.next();// Keyisbitmask // Serversocketchannelhaspendingconnectionrequests? if (key.isAcceptable()) { protocol.handleAccept(key); } // Clientsocketchannelhaspendingdata? if (key.isReadable()) { protocol.handleRead(key); } // Clientsocketchannelisavailableforwritingand // keyisvalid(i.e.,channelnotclosed)? if (key.isValid() && key.isWritable()) { protocol.handleWrite(key); } keyIter.remove();// removefromsetofselectedkeys } } } }

我們通過listnChannel.register(selector, SelectionKey.OP_ACCEPT); 注冊了一個我們感興趣的事件,然后調用selector.select(TIMEOUT)等待訂閱的時間發生,然后再采取相應的處理措施。

***我們實現EchoSelectorProtocol

package com.cnblogs.gpcuster;  import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.nio.channels.ServerSocketChannel; import java.nio.ByteBuffer; import java.io.IOException;  public class EchoSelectorProtocol implements TCPProtocol { private int bufSize;// SizeofI/Obuffer  public EchoSelectorProtocol(int bufSize) { this.bufSize = bufSize; }  public void handleAccept(SelectionKey key) throws IOException { SocketChannel clntChan = ((ServerSocketChannel) key.channel()).accept(); clntChan.configureBlocking(false);// Mustbenonblockingtoregister // Registertheselectorwithnewchannelforreadandattachbytebuffer clntChan.register(key.selector(), SelectionKey.OP_READ, ByteBuffer .allocate(bufSize)); }  public void handleRead(SelectionKey key) throws IOException { // Clientsocketchannelhaspendingdata SocketChannel clntChan = (SocketChannel) key.channel(); ByteBuffer buf = (ByteBuffer) key.attachment(); long bytesRead = clntChan.read(buf); if (bytesRead == -1) {// Didtheotherendclose? clntChan.close(); } else if (bytesRead > 0) { // Indicateviakeythatreading/writingarebothofinterestnow. key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); } }  public void handleWrite(SelectionKey key) throws IOException { /* * Channelisavailableforwriting,andkeyisvalid(i.e.,clientchannel * notclosed). */ // Retrievedatareadearlier ByteBuffer buf = (ByteBuffer) key.attachment(); buf.flip();// Preparebufferforwriting SocketChannel clntChan = (SocketChannel) key.channel(); clntChan.write(buf); if (!buf.hasRemaining()) {// Buffercompletelywritten? // Nothingleft,sonolongerinterestedinwrites key.interestOps(SelectionKey.OP_READ); } buf.compact();// Makeroomformoredatatobereadin } }

上述內容就是Java中怎么使用NIO實現網絡編程,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節
推薦閱讀:
  1. Java NIO
  2. java中的NIO介紹

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

丽江市| 河源市| 商都县| 商河县| 滨州市| 布拖县| 揭东县| 沁水县| 陇南市| 上栗县| 静安区| 河南省| 宜丰县| 溧阳市| 巢湖市| 平遥县| 曲沃县| 和政县| 宿迁市| 广宗县| 乌拉特后旗| 靖宇县| 滕州市| 老河口市| 兴仁县| 会东县| 新源县| 和龙市| 奉新县| 牡丹江市| 南宁市| 光山县| 泰来县| 松滋市| 晋江市| 平陆县| 上饶市| 藁城市| 叶城县| 池州市| 南安市|