1. 程式人生 > >1、OIO與NIO程式碼示例比較

1、OIO與NIO程式碼示例比較

  • 傳統socket服務端,程式碼示例
package OIO;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * 傳統socket服務端
 *  */
public class OioServer {

    @SuppressWarnings
("resource") public static void main(String[] args) throws Exception { ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(); //建立socket服務,監聽10101埠 ServerSocket server=new ServerSocket(10101); System.out.println("伺服器啟動!"); while(true){ //獲取一個套接字(阻塞)
final Socket socket = server.accept(); System.out.println("來個一個新客戶端!"); newCachedThreadPool.execute(new Runnable() { @Override public void run() { //業務處理 handler(socket); } }); } } /** * 讀取資料 * @param
socket * @throws Exception */
public static void handler(Socket socket){ try { byte[] bytes = new byte[1024]; InputStream inputStream = socket.getInputStream(); while(true){ //讀取資料(阻塞) int read = inputStream.read(bytes); if(read != -1){ System.out.println(new String(bytes, 0, read)); }else{ break; } } } catch (Exception e) { e.printStackTrace(); }finally{ try { System.out.println("socket關閉"); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
  • NIO服務端,程式碼示例
package NIO;

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;

/**
 * NIO服務端
 */
public class NIOServer {
    // 通道管理器
    private Selector selector;

    /**
     * 獲得一個ServerSocket通道,並對該通道做一些初始化的工作
     * 
     * @param port
     *            繫結的埠號
     * @throws IOException
     */
    public void initServer(int port) throws IOException {
        // 獲得一個ServerSocket通道
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        // 設定通道為非阻塞
        serverChannel.configureBlocking(false);
        // 將該通道對應的ServerSocket繫結到port埠
        serverChannel.socket().bind(new InetSocketAddress(port));
        // 獲得一個通道管理器
        this.selector = Selector.open();
        // 將通道管理器和該通道繫結,併為該通道註冊SelectionKey.OP_ACCEPT事件,註冊該事件後,
        // 當該事件到達時,selector.select()會返回,如果該事件沒到達selector.select()會一直阻塞。
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    }

    /**
     * 採用輪詢的方式監聽selector上是否有需要處理的事件,如果有,則進行處理
     * 
     * @throws IOException
     */
    public void listen() throws IOException {
        System.out.println("服務端啟動成功!");
        // 輪詢訪問selector
        while (true) {
            // 當註冊的事件到達時,方法返回;否則,該方法會一直阻塞
            selector.select();
            //selector.select(10000);
            //selector.wakeup();
            // 獲得selector中選中的項的迭代器,選中的項為註冊的事件
            Iterator<?> ite = this.selector.selectedKeys().iterator();
            while (ite.hasNext()) {
                SelectionKey key = (SelectionKey) ite.next();
                // 刪除已選的key,以防重複處理
                ite.remove();

                handler(key);
            }
        }
    }

    /**
     * 處理請求
     * 
     * @param key
     * @throws IOException
     */
    public void handler(SelectionKey key) throws IOException {

        // 客戶端請求連線事件
        if (key.isAcceptable()) {
            handlerAccept(key);
            // 獲得了可讀的事件
        } else if (key.isReadable()) {
            handelerRead(key);
        }
    }

    /**
     * 處理連線請求
     * 
     * @param key
     * @throws IOException
     */
    public void handlerAccept(SelectionKey key) throws IOException {
        ServerSocketChannel server = (ServerSocketChannel) key.channel();
        // 獲得和客戶端連線的通道
        SocketChannel channel = server.accept();
        // 設定成非阻塞
        channel.configureBlocking(false);

        // 在這裡可以給客戶端傳送資訊哦
        System.out.println("新的客戶端連線");
        // 在和客戶端連線成功之後,為了可以接收到客戶端的資訊,需要給通道設定讀的許可權。
        channel.register(this.selector, SelectionKey.OP_READ);
    }

    /**
     * 處理讀的事件
     * 
     * @param key
     * @throws IOException
     */
    public void handelerRead(SelectionKey key) throws IOException {
        // 伺服器可讀取訊息:得到事件發生的Socket通道
        SocketChannel channel = (SocketChannel) key.channel();
        // 建立讀取的緩衝區
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int read = channel.read(buffer);
        if(read > 0){
            byte[] data = buffer.array();
            String msg = new String(data).trim();
            System.out.println("服務端收到資訊:" + msg);

            //回寫資料
            ByteBuffer outBuffer = ByteBuffer.wrap("好的".getBytes());
            channel.write(outBuffer);// 將訊息回送給客戶端
        }else{
            System.out.println("客戶端關閉");
            key.cancel();
        }
    }

    /**
     * 啟動服務端測試
     * 
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        NIOServer server = new NIOServer();
        server.initServer(8000);
        server.listen();
    }

}