Java Socket NIO樣本總結

來源:互聯網
上載者:User

標籤:

Java NIO是非阻塞IO的實現,基於事件驅動,非常適用於伺服器需要維持大量串連,但是資料交換量不大的情況,例如一些即時通訊的服務等等,它主要有三個部分組成:

  • Channels
  • Buffers
  • Selectors

Channel有兩種ServerSocketChannel 和 SocketChannel,ServerSocketChannel可以監聽新加入的Socket串連,SocketChannel用於讀和寫操作。NIO總是把緩衝區的資料寫入通道,或者把通道裡的資料讀出到緩衝區。

Buffer本質上是一塊用於讀寫的記憶體,只是被封裝成了buffer對象,你可以通過allocateDirect()或者allocate()申請記憶體空間(allocate分配方式產生的記憶體開銷是在JVM中的,而allocateDirect的分配方式產生的開銷在JVM之外,以就是系統級的記憶體配置,使用allocateDirect尤其注意記憶體溢出問題),Buffer尤其需要理解三個概念,

capacity、position、limit,capacity是固定大小,position是當前讀寫位置,limit是一個類似於門限的值,用於控制讀寫的最大的位置。Buffer的常用方法有clear、compact、flip等等,還有比如Buffer的靜態方法wrap等等,這些需要根據capacity、position、limit的值進行理解,上面ifeve上的文章就很詳細了,我就不再累述了。

Selector用於檢測通道,我們通過它才知道哪個通道發生了哪個事件,所以如果需要用selector的話就需要首先進行register,然後遍曆SelectionKey對事件進行處理。它一共有SelectionKey.OP_CONNECT、SelectionKey.OP_ACCEPT、SelectionKey.OP_READ、SelectionKey.OP_WRITE四種事件類型。

我在這裡只是粗略的總結,關於NIO的概念 http://ifeve.com/java-nio-all/ 可以看這裡。

http://blog.csdn.net/ns_code/article/details/15545057 蘭亭風雨的這個demo不錯,我直接照搬過來了。

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 NIOServer {        private static int BUFF_SIZE=1024;    private static int TIME_OUT = 2000;    public static void main(String[] args) throws IOException {                Selector selector = Selector.open();        ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();        serverSocketChannel.bind(new InetSocketAddress(10083));        serverSocketChannel.configureBlocking(false);        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);                TCPProtocol protocol = new EchoSelectorProtocol(BUFF_SIZE);                 while (true) {            if(selector.select(TIME_OUT)==0){                //在等待通道準備的同時,也可以非同步地執行其他任務,  這裡列印*                System.out.print("*");                  continue;              }            Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();            while (keyIter.hasNext()) {                SelectionKey key = keyIter.next();                 //如果服務端通道感興趣的I/O操作為accept                  if (key.isAcceptable()){                      protocol.handleAccept(key);                  }                  //如果用戶端通道感興趣的I/O操作為read                  if (key.isReadable()){                      protocol.handleRead(key);                  }                  //如果該索引值有效,並且其對應的用戶端通道感興趣的I/O操作為write                  if (key.isValid() && key.isWritable()) {                      protocol.handleWrite(key);                  }                                //這裡需要手動從鍵集中移除當前的key                  keyIter.remove();             }                    }    }}
import java.io.IOException;import java.nio.channels.SelectionKey;public interface TCPProtocol {    void handleAccept(SelectionKey key) throws IOException;    void handleRead(SelectionKey key) throws IOException;    void handleWrite(SelectionKey key) throws IOException;}
import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;public class EchoSelectorProtocol implements TCPProtocol {        private int bufSize; // 緩衝區的長度      public EchoSelectorProtocol(int bufSize){      this.bufSize = bufSize;      }    @Override    public void handleAccept(SelectionKey key) throws IOException {        System.out.println("Accept");        SocketChannel socketChannel = ((ServerSocketChannel)key.channel()).accept();        socketChannel.configureBlocking(false);        socketChannel.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufSize));            }    @Override    public void handleRead(SelectionKey key) throws IOException {        SocketChannel clntChan = (SocketChannel) key.channel();          //擷取該通道所關聯的附件,這裡為緩衝區          ByteBuffer buf = (ByteBuffer) key.attachment();        buf.clear();        long bytesRead = clntChan.read(buf);        //如果read()方法返回-1,說明用戶端關閉了串連,那麼用戶端已經接收到了與自己發送位元組數相等的資料,可以安全地關閉          if (bytesRead == -1){               clntChan.close();          }else if(bytesRead > 0){            //如果緩衝區總讀入了資料,則將該通道感興趣的操作設定為為可讀可寫              key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);          }              }    @Override    public void handleWrite(SelectionKey key) throws IOException {        // TODO Auto-generated method stub        ByteBuffer buffer=(ByteBuffer) key.attachment();        buffer.flip();        SocketChannel clntChan = (SocketChannel) key.channel();          //將資料寫入到通道中          clntChan.write(buffer);          if (!buffer.hasRemaining()){                    //如果緩衝區中的資料已經全部寫入了通道,則將該通道感興趣的操作設定為可讀            key.interestOps(SelectionKey.OP_READ);          }         //為讀入更多的資料騰出空間          buffer.compact();               }} 
import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SocketChannel;public class NIOClient {        public static void main(String[] args) throws IOException {        SocketChannel clntChan = SocketChannel.open();        clntChan.configureBlocking(false);        if (!clntChan.connect(new InetSocketAddress("localhost", 10083))){              //不斷地輪詢串連狀態,直到完成串連              while (!clntChan.finishConnect()){                  //在等待串連的時間裡,可以執行其他任務,以充分發揮非阻塞IO的非同步特性                  //這裡為了示範該方法的使用,只是一直列印"."                  System.out.print(".");                }           }                //為了與後面列印的"."區別開來,這裡輸出分行符號          System.out.print("\n");          //分別執行個體化用來讀寫的緩衝區                  ByteBuffer writeBuf = ByteBuffer.wrap("send send send".getBytes());        ByteBuffer readBuf = ByteBuffer.allocate("send".getBytes().length-1);                while (writeBuf.hasRemaining()) {            //如果用來向通道中寫資料的緩衝區中還有剩餘的位元組,則繼續將資料寫入通道                  clntChan.write(writeBuf);                      }        StringBuffer stringBuffer=new StringBuffer();         //如果read()接收到-1,表明服務端關閉,拋出異常              while ((clntChan.read(readBuf)) >0){                readBuf.flip();                stringBuffer.append(new String(readBuf.array(),0,readBuf.limit()));                readBuf.clear();            }                //列印出接收到的資料          System.out.println("Client Received: " +  stringBuffer.toString());          //關閉通道          clntChan.close();      }}

 

Java Socket NIO樣本總結

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.