NIO编程

来源:互联网 发布:淘宝自刷平台 编辑:程序博客网 时间:2024/06/07 05:47

这里首先声明:我导入的jar包是5.0的jar包。

在写这个demo之前最好先学习一下NIO 的基础方法,至少知道哪个方法是干什么用的。

这篇博文的代码实现了一个简单的时间服务器:客户端发送请求,服务端判断接收到的请求返回不同的信息。

NIO服务端代码:

public class TimeServer {public static void main(String[] args) {int port = 9090;if(args!=null&&args.length>0){try{port = Integer.valueOf(args[0]);}catch(NumberFormatException e){//采用默认值}}/** * 创建一个多路复用类,它是一个独立的线程,负责轮询多路复用器Selector * 可以处理多个客户端的并发接入 */MultiplexerTimeServer timeServer = new MultiplexerTimeServer(port);new Thread(timeServer,"NIO-MultiplexerTimeServer-001").start();}

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;import java.util.Set;public class MultiplexerTimeServer implements Runnable {private Selector selector;private ServerSocketChannel servChannel;private volatile boolean stop;/** * 初始化多路复用器、绑定监听窗口 *  * @param port */public MultiplexerTimeServer(int port) {try {//多路复用器,可以同时轮询多个Channelselector = Selector.open();//打开ServerSocketChannel,用于监听客户端的连接servChannel = ServerSocketChannel.open();//绑定监听的端口,设置连接为非阻塞模式servChannel.configureBlocking(false);servChannel.socket().bind(new InetSocketAddress(port), 1024);//将ServerSocketChannel注册到多路复用器上,监听ACCEPT事件servChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("The time server is start in port :" + port);} catch (IOException e) {e.printStackTrace();System.exit(1);}}public void stop() {this.stop = true;}@Overridepublic void run() {while (!stop) {try {//多路复用器在线程run方法的无限循环体内轮询准备就绪的Keyselector.select(1000);Set<SelectionKey> selectionKey = selector.selectedKeys();Iterator<SelectionKey> it = selectionKey.iterator();SelectionKey key = null;while (it.hasNext()) {key = it.next();it.remove();try {handleInput(key);} catch (Exception e) {key.channel();if (key.channel() != null)key.channel().close();}}} catch (Throwable t) {t.printStackTrace();}}/** * 多路复用器关闭后,所有注册在上面的Channel和Pipe等资源都会被自动去注册 并关闭,所以不需要重复释放资源 */if (selector != null) {try {selector.close();} catch (IOException e) {e.printStackTrace();}}}private void handleInput(SelectionKey key) throws IOException {if(key.isValid()){//处理新接入的请求消息if(key.isAcceptable()){//接收新的连接ServerSocketChannel ssc = (ServerSocketChannel) key.channel();SocketChannel sc = ssc.accept();sc.configureBlocking(false);//添加新的连接到多路复用器sc.register(selector, SelectionKey.OP_READ);}if(key.isReadable()){//读取数据SocketChannel sc = (SocketChannel) key.channel();ByteBuffer readBuffer = ByteBuffer.allocate(1024);int readBytes = sc.read(readBuffer);if(readBytes>0){readBuffer.flip();byte[] bytes = new byte[readBuffer.remaining()];readBuffer.get(bytes);String body = new String(bytes, "utf-8");System.out.println("The time server receive order :"+body);String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body)?new java.util.Date(System.currentTimeMillis()).toString():"BAD ORDER";doWrite(sc,currentTime);}else if(readBytes<0){//对端关闭连接key.channel();sc.close();}else {;//读到0字节,忽略}}}}private void doWrite(SocketChannel channel, String response) throws IOException {if(response!=null&&response.trim().length()>0){byte[] bytes = response.getBytes();ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);writeBuffer.put(bytes);writeBuffer.flip();channel.write(writeBuffer);}}}

NIO客户端代码:

public class TimeClient {    public static void main(String[] args) {        int port = 9090;        if(args!=null&&args.length>0){            try{                port = Integer.valueOf(args[0]);            }catch(NumberFormatException e){                //采用默认值            }        }        new Thread(new TimeClientHandle("127.0.0.1",port),"TimeClient-001").start();    }}

public class TimeClientHandle implements Runnable{    private String host;    private int port;    private Selector selector;    private SocketChannel socketChannel;    private volatile boolean stop;    public TimeClientHandle(String host,int port){        this.host = host==null?"127.0.0.1":host;        this.port = port;        try {            selector = Selector.open();            socketChannel = SocketChannel.open();            socketChannel.configureBlocking(false);        }catch (IOException e){            e.printStackTrace();            System.exit(1);        }    }    @Override    public void run() {        try {            doConnect();        }catch (IOException e){            e.printStackTrace();            System.exit(1);        }        while (!stop){            try{                selector.select(1000);                Set<SelectionKey> selectionKey = selector.selectedKeys();                Iterator<SelectionKey> it = selectionKey.iterator();                SelectionKey key = null;                while (it.hasNext()){                    key = it.next();                    it.remove();                    try {                        handleInput(key);                    }catch (Exception e){                        if(key!=null){                            key.cancel();                            if (key.channel()!=null)                                key.channel().close();                        }                    }                }            }catch (Exception e){                e.printStackTrace();                System.exit(1);            }        }        /**         * 多路复用器关闭后,所有注册在上面的Channel和Pipe等资源都会被自动去注册 并关闭,所以不需要重复释放资源         */        if (selector != null) {            try {                selector.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }        private void handleInput(SelectionKey key) throws IOException{        if (key.isValid()){            //判断是否连接成功            SocketChannel sc = (SocketChannel) key.channel();            if (key.isConnectable()) {                System.out.println("连接成功...");                if (sc.finishConnect()) {                    sc.register(selector, SelectionKey.OP_READ);                    doWrite(sc);                } else                    System.exit(1);            }                if (key.isReadable()){                    ByteBuffer readBuffer = ByteBuffer.allocate(1024);                    int readBytes = sc.read(readBuffer);                    if (readBytes>0){                        readBuffer.flip();                        byte[] bytes = new byte[readBuffer.remaining()];                        readBuffer.get(bytes);                        String body = new String(bytes,"UTF-8");                        System.out.println("Now is :"+body);                        this.stop = true;                    }else if(readBytes<0){                        //对端链路关闭                        key.channel();                        sc.close();                    }else                        ;   //读到0字节,忽略                }            }        }    private void doConnect() throws IOException{        //如果连接成功,则注册到多路复用器上,发送请求消息,读应答        if(socketChannel.connect(new InetSocketAddress(host,port))){            socketChannel.register(selector,SelectionKey.OP_READ);            doWrite(socketChannel);        }else            socketChannel.register(selector,SelectionKey.OP_CONNECT);    }    private void doWrite(SocketChannel sc) throws  IOException{        byte[] req = "QUERY TIME ORDER".getBytes();        ByteBuffer writeBuffer = ByteBuffer.allocate(req.length);        writeBuffer.put(req);        writeBuffer.flip();        sc.write(writeBuffer);        if(!writeBuffer.hasRemaining()){            System.out.println("Send order 2 server succeed.");        }    }}


原创粉丝点击