Nio的基础与使用

来源:互联网 发布:收费软件炒股最好 编辑:程序博客网 时间:2024/06/08 10:33

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;}@Overridepublic 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);}}