Nio的基礎與使用

Nio的介紹

nio是指jdk1.4 及以上版本里提供的新api(New IO) ,爲所有的原始類型(boolean類型除外)提供緩存支持的數據容器,使用它可以提供非阻塞式的高伸縮性網絡

nio裏面最重要的三個對象

  1. Buffer 緩存區
  2. channel 通道
  3. selector 選擇器

nio的常用方法

  1. buffer.flip()改變position和limit的值,就是傳統說的把寫變成讀,把讀變成寫。
  2. buffer.clear()清除buffer,buffer.compact()也是清除,只是清除已讀
  3. Selector.select()監聽註冊通道.
  4. Selector.selectKeys獲取事件中的SelectKey
  5. channel.register()把通道註冊到Selector,並指定你要監聽的事件

Nio的使用

使用nio操作文件

拷貝a.txt的內容到b.txt

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * Created by tannent on 11/14/17.
 */
public class CopyFile {
public static void main(String []args) throws IOException {
    //打開文件輸入流
    FileInputStream inputStream=new FileInputStream(new File("D:\\a.txt"));
    //從輸入流中獲取通道
    FileChannel inputChannel= inputStream.getChannel();
    //打開文件輸出流
    FileOutputStream outputStream=new FileOutputStream(new File("D:\\b.txt"));
    //從輸出流獲取通道
    FileChannel outChannel=outputStream.getChannel();
    //創建一個字節緩存區
    ByteBuffer buffer=ByteBuffer.allocate(1024);
    while(true){
        int n=inputChannel.read(buffer);
        if(n<=0){
            break;
        }
        //使讀模式改成寫模式,其實就是改變Position,Limit的值,
        // 把position的值賦給limit,然後把position設置爲0
        buffer.flip();
        //向輸出通道寫入
        outChannel.write(buffer);
        //清空緩存區
        buffer.clear();
    }
        outChannel.close();
        inputChannel.close();
        outputStream.close();
        inputStream.close();
    }
}

使用Nio進行網絡通信

簡單的使用,通過客戶端發送信息,服務端回消息給客戶端

客戶端代碼
import sun.beans.editors.ByteEditor;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

/**
     * Created by tannent on 11/14/17.
 */
public class NioClient {
    public static void main(String[] args) throws IOException {
    SocketChannel socketChannel=SocketChannel.open();
    socketChannel.connect(new InetSocketAddress("localhost",8088));
    ByteBuffer byteBuffer= ByteBuffer.wrap("連接服務器".getBytes());
    socketChannel.write(byteBuffer);
    socketChannel.socket().shutdownOutput();
    ByteBuffer outBuffer=ByteBuffer.allocate(1024);
    byte[] bytes;
    int n=0;
    String str="";
    while((n=socketChannel.read(outBuffer))>0){
        outBuffer.flip();
        bytes=new byte[n];
        outBuffer.get(bytes);
        str+=new String(bytes);
        outBuffer.clear();
    }
        System.out.println(str);
        socketChannel.socket().shutdownInput();
        socketChannel.socket().close();
        socketChannel.close();
       }
}
服務端代碼
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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;

/**
     * Created by tannent on 11/14/17.
 */
public class Server {
public static void main(String[] args) throws IOException {
    Selector selector=Selector.open();
    ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
    ServerSocket serverSocket= serverSocketChannel.socket();
    serverSocket.bind(new InetSocketAddress(8088));
    serverSocketChannel.configureBlocking(false);
    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    while(true){
        int num=selector.select();
        if(num>0){
            Set<SelectionKey> selectionKeys=selector.selectedKeys();
            Iterator<SelectionKey> selectionKeyIterator=selectionKeys.iterator();
            while (selectionKeyIterator.hasNext()){
                SelectionKey selectionKey=selectionKeyIterator.next();
                if(selectionKey.isAcceptable()){
                    ServerSocketChannel serverSocketChannel1= (ServerSocketChannel) selectionKey.channel();
                    SocketChannel socketChannel=serverSocketChannel1.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector,SelectionKey.OP_READ);
                    selectionKeyIterator.remove();
                }else if(selectionKey.isReadable()){
                    ByteBuffer buffer=ByteBuffer.allocate(1024);
                    SocketChannel socketChannel= (SocketChannel) selectionKey.channel();
                    int n=0;
                    byte[] bytes;
                    String str="服務器響應,你的連接信息是    ";
                    while ((n=socketChannel.read(buffer))>0){
                        buffer.flip();
                        bytes=new byte[n];
                        buffer.get(bytes);
                        str+=new String(bytes);
                        buffer.clear();
                    }

                    socketChannel.write(ByteBuffer.wrap(str.getBytes()));
                    socketChannel.close();
                    selectionKeyIterator.remove();
                }
            }
        }
    }
   }
}

案例2 客戶端通過服務器轉發數據進行客戶端之間的通訊

客戶端代碼
import com.sun.org.apache.bcel.internal.generic.Select;
import sun.beans.editors.ByteEditor;

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;

/**
     * Created by tannent on 11/14/17.
 */
public class NioClient {

SocketChannel socketChannel;
public NioClient(String num)  {

    Selector selector= null;
    try {

        selector = Selector.open();
        socketChannel=SocketChannel.open();
        socketChannel.connect(new InetSocketAddress("localhost",8088));
        socketChannel.configureBlocking(false);
        socketChannel.register(selector, SelectionKey.OP_READ);

        ClientThread clientThread=new ClientThread();
        clientThread.setSelector(selector);

        new Thread(clientThread).start();
        sendMsg(MessageType.LOGIN+"#"+num+"#0#你好");
    } catch (IOException e) {
        e.printStackTrace();
    }

}
public void sendMsg(String msg){
    try {

        socketChannel.write(ByteBuffer.wrap(msg.getBytes()));
    } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
客戶端接受消息的線程
import java.io.IOException;
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;

/**
     * Created by tannent on 11/14/17.
 */
public class ClientThread implements Runnable {
public static int i=0;
private Selector selector;
public void setSelector(Selector selector) {
    this.selector = selector;
}

@Override
public void run() {

        try {
            while (selector.select()>0) {
                Set<SelectionKey> selectionKeySet = selector.selectedKeys();
                Iterator<SelectionKey> selectionKeyIterator = selectionKeySet.iterator();
                while (selectionKeyIterator.hasNext()) {
                    SelectionKey key = selectionKeyIterator.next();
                    if (key.isReadable()) {
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        ByteBuffer outBuffer = ByteBuffer.allocate(1024);
                        byte[] bytes;
                        int n = 0;
                        String str = "";
                        while ((n = socketChannel.read(outBuffer)) > 0) {
                            outBuffer.flip();
                            bytes = new byte[n];
                            outBuffer.get(bytes);
                            str += new String(bytes);
                            outBuffer.clear();
                        }
                       // key.interestOps(SelectionKey.OP_READ);
                        System.out.println(str);
                        selector.selectedKeys().remove(key);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }



}
}
服務端代碼
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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;

/**
     * Created by tannent on 11/14/17.
 */
public class Server {
public static int i=0;
public static void main(String[] args) throws IOException {
    Selector selector=Selector.open();
    ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
    ServerSocket serverSocket= serverSocketChannel.socket();
    serverSocket.bind(new InetSocketAddress(8088));
    serverSocketChannel.configureBlocking(false);
    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    while(true){
        int num=selector.select();
        if(num>0){
            Set<SelectionKey> selectionKeys=selector.selectedKeys();
            Iterator<SelectionKey> selectionKeyIterator=selectionKeys.iterator();
            while (selectionKeyIterator.hasNext()){
                SelectionKey selectionKey=selectionKeyIterator.next();
                if(selectionKey.isAcceptable()){
                    ServerSocketChannel serverSocketChannel1= (ServerSocketChannel) selectionKey.channel();
                    SocketChannel socketChannel=serverSocketChannel1.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector,SelectionKey.OP_READ|SelectionKey.OP_WRITE,ByteBuffer.allocate(1024));
                    selectionKeyIterator.remove();
                }else if(selectionKey.isReadable()){


                    ByteBuffer buffer=(ByteBuffer)selectionKey.attachment();
                    buffer.clear();
                    SocketChannel socketChannel= (SocketChannel) selectionKey.channel();
                    int n=0;
                    byte[] bytes;
                    String str="";
                    while ((n=socketChannel.read(buffer))>0){
                        if(n==-1){
                            socketChannel.close();
                        }
                        buffer.flip();
                        bytes=new byte[n];
                        buffer.get(bytes);
                        str+=new String(bytes);
                        buffer.clear();
                    }
                    System.out.println(str);
                    String[] strings=str.split("#");
                    for (String str1:strings
                         ) {
                        System.out.println(str1);
                    }
                    if(strings[0].equals("1")){
                        SocketChannelManage.addSocketChannel(strings[1],socketChannel);
                    }else {
                        System.out.println("發送消息");
                        SocketChannelManage.getSocketChannel(strings[2]).write(ByteBuffer.wrap((strings[1]+"發來消息"+strings[3]).getBytes()));
                        System.out.println("發送消息");
                    }

                   // selectionKey.interestOps(SelectionKey.OP_READ);
                    selectionKeyIterator.remove();
                }
            }
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
}
發送消息的類型
public final class MessageType {
private  MessageType(){}
public static final int LOGIN=1;
public static final int MESSAGE=2;}
服務端channel管理的類
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Map;

public class SocketChannelManage {
private static Map<String,SocketChannel> socketChannelMap=new HashMap<>();
private SocketChannelManage(){}
public static void addSocketChannel(String key,SocketChannel socketChannel){
    if(socketChannelMap.containsKey(key))
        return;
    socketChannelMap.put(key,socketChannel);
}
public static void removeSocketChannel(String key){
    socketChannelMap.remove(key);
}
public static SocketChannel getSocketChannel(String key){
    return  socketChannelMap.get(key);
}
}
發佈了29 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章