1. 程式人生 > >Java傳統IO / NIO基礎知識

Java傳統IO / NIO基礎知識

1.IO的基本操作

只執行緒情況下只能有一個客戶端的連線

package xss.netty.basicio;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * java 原生的IO處理方式
 * IO Server
 */
public class IOMainServerTest {

    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket=new ServerSocket(9999);
        System.out.println("server start.......");
        while (true){
            // 會阻塞client的連線,只到client的訊息處理完
            //也就是說一次只能處理一個客戶端的請求
            Socket socket=serverSocket.accept();
            System.out.println("new client connect");
            handler(socket);
        }
    }

    public static  void handler(Socket socket) {
        try{
            InputStream inputStream=socket.getInputStream();
            byte[] readBytes=new byte[1024];
            while(true){
                int reads =inputStream.read(readBytes);//阻塞資料的讀取
                if(reads != -1){
                    System.out.println("message ->"+new String(readBytes,0,reads));
                }else{
                    break;
                }
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }finally {
            try {
                System.out.println("socket closed.");
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

}

可多客戶端的同時連線

package xss.netty.basicio;

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;

/**
 * java 原生的IO處理方式
 *  改進之一:服務端可以同時接收多個客戶端的請求
 *
 */
public class IOMainServerMutliClientTest {

    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket=new ServerSocket(9999);
        System.out.println("server start.......");
        ExecutorService  executors= Executors.newCachedThreadPool();
        while (true){
            // 會阻塞client的連線,只到client的訊息處理完
            //也就是說一次只能處理一個客戶端的請求
            final Socket socket=serverSocket.accept();
            System.out.println("new client connect");
            executors.execute(new Runnable() {
                public void run() {
                    handler(socket);
                }
            });
        }
    }

    public static  void handler(Socket socket) {
        try{
            InputStream inputStream=socket.getInputStream();
            byte[] readBytes=new byte[1024];
            while(true){
                int reads =inputStream.read(readBytes);//阻塞資料的讀取
                if(reads != -1){
                    System.out.println("message ->"+new String(readBytes,0,reads));
                }else{
                    break;
                }
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }finally {
            try {
                System.out.println("socket closed.");
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

}

2.NIO的基本操作

package xss.netty.basicio;

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 NIOMainServerTest {
    //通道的管理,監聽客戶傳送的事件
    private Selector selector;

    public static void main(String[] args) throws  Exception{
        NIOMainServerTest serverTest=new NIOMainServerTest();
        serverTest.initServer(9999);
        serverTest.listen();
        System.out.println("main executed.");
    }

    /**
     * 初始化ServerSocket 通道
     * @param port
     * @throws IOException
     */
    public void initServer(int port) throws IOException{
        ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
        //設定為非阻塞通道
        serverSocketChannel.configureBlocking(false);
        //繫結埠
        serverSocketChannel.socket().bind(new InetSocketAddress(port));
        //
        this.selector=Selector.open();
        //將selector 與 通道進行繫結,並且註冊ACCEPT事件
        //selector會阻塞監聽是否有ACCEPT事件的到達。Selector.select()
        serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
        System.out.println("Server init finished with prot="+port);
    }

    /**
     * 輪詢監聽selector上是否有需要處理的事件
     * @throws IOException
     */
    public void listen() throws  IOException{
        System.out.println("start listen...");
        while (true){
            //當註冊的事件到達時,方法返回;否則,該方法會一直阻塞
            selector.select();
            //獲得selector中選中的項的迭代器,選中的項為註冊的事件
            Iterator iterator=this.selector.selectedKeys().iterator();
            while(iterator.hasNext()){
                SelectionKey selectionKey=(SelectionKey)iterator.next();
                iterator.remove();//刪除已選的key,以防重複處理
                //處理請求
                this.handler(selectionKey);
            }
        }
    }
    /**
     * 事件型別請求的處理
     * @param key
     * @throws IOException
     */
    public void handler(SelectionKey key) throws  IOException{
        if(key.isAcceptable()){
            //客戶端的連線請求事件
            handlerAccept(key);
        }else  if(key.isReadable()){
            //處理客戶端傳送的資料
            handelerRead(key);
        }
    }

    public void handlerAccept(SelectionKey key) throws IOException {
        ServerSocketChannel serverSocketChannel=(ServerSocketChannel) key.channel();
        //建立與客戶端連線的通道
        SocketChannel channel=serverSocketChannel.accept();
        channel.configureBlocking(false);
        //給selector 繫結客戶端,並且監聽客戶端傳送的請求。即對於服務端來說是可讀取到客戶端的資料
        //請求
        channel.register(this.selector,SelectionKey.OP_READ);
        System.out.println("New Client connected");
    }

    public void handelerRead(SelectionKey key) throws IOException {
        SocketChannel channel=(SocketChannel)key.channel();
        //緩衝區的大小以實際情況來調整
        ByteBuffer byteBuffer= ByteBuffer.allocate(1024);
        //讀取資料, -- 示例客戶端最大一次性發送1024
        int read=channel.read(byteBuffer);
        if(read>0){
            String readMsg=new String(byteBuffer.array());
            System.out.println("Read message:"+readMsg);
            //響應客戶端
            ByteBuffer outBuffer=ByteBuffer.wrap((readMsg+" is Ok").getBytes());
            channel.write(outBuffer);
        }else{
            System.out.println("client closed.");
            key.cancel();
        }
    }
}

作業系統IO Selector 模型類似