• Java NIO 同步非阻塞应用实例


    一、server:

    package org.windwant.nio;
    
    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;
    
    /**
     * ServerSocketChannel
     */
    public class NIOServer {
        /*标识数字*/
        private int flag = 0;
        /*缓冲区大小*/
        private int BLOCK = 2048;
        /*接受数据缓冲区*/
        private ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);
        /*发送数据缓冲区*/
        private ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);
        private Selector selector;
    
        public NIOServer(int port) throws IOException {
            // 打开服务器套接字通道
    
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            // 服务器配置为非阻塞
    
            serverSocketChannel.configureBlocking(false);
            // 检索与此通道关联的服务器套接字
    
            ServerSocket serverSocket = serverSocketChannel.socket();
            // 进行服务的绑定
    
            serverSocket.bind(new InetSocketAddress(port));
            // 通过open()方法找到Selector
    
            selector = Selector.open();
            // 注册到selector,等待连接
    
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("Server Start----8888:");
        }
    
    
        // 监听
    
        private void listen() throws IOException {
            while (true) {
                // 选择一组键,并且相应的通道已经打开
    
                selector.select();
                // 返回此选择器的已选择键集。
    
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    iterator.remove();
                    handleKey(selectionKey);
                }
            }
        }
    
        // 处理请求
    
        private void handleKey(SelectionKey selectionKey) throws IOException {
            // 接受请求
    
            ServerSocketChannel server = null;
            SocketChannel client = null;
            String receiveText;
            String sendText;
            int count=0;
            // 测试此键的通道是否已准备好接受新的套接字连接。
    
            if (selectionKey.isAcceptable()) {
                // 返回为之创建此键的通道。
    
                server = (ServerSocketChannel) selectionKey.channel();
                // 接受到此通道套接字的连接。
    
                // 此方法返回的套接字通道(如果有)将处于阻塞模式。
    
                client = server.accept();
                // 配置为非阻塞
    
                client.configureBlocking(false);
                // 注册到selector,等待连接
    
                client.register(selector, SelectionKey.OP_READ);
            } else if (selectionKey.isReadable()) {
                // 返回为之创建此键的通道。
    
                client = (SocketChannel) selectionKey.channel();
                //将缓冲区清空以备下次读取
    
                receivebuffer.clear();
                //读取服务器发送来的数据到缓冲区中
    
                count = client.read(receivebuffer);
                if (count > 0) {
                    receiveText = new String( receivebuffer.array(),0,count);
                    System.out.println("服务器端接受客户端数据--:"+receiveText);
                    client.register(selector, SelectionKey.OP_WRITE);
                }
            } else if (selectionKey.isWritable()) {
                //将缓冲区清空以备下次写入
    
                sendbuffer.clear();
                // 返回为之创建此键的通道。
    
                client = (SocketChannel) selectionKey.channel();
    
    
                sendText = "<h1>message from server: this is the test message!</h1>";
    
    //            sendText="message from server--" + flag++;
                //向缓冲区中输入数据
    
                sendbuffer.put(sendText.getBytes());
                //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
    
                sendbuffer.flip();
                //输出到通道
    
                client.write(sendbuffer);
                System.out.println("服务器端向客户端发送数据--:"+sendText);
                client.register(selector, SelectionKey.OP_READ);
            }
        }
    
        /**
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            int port = 8888;
            NIOServer server = new NIOServer(port);
            server.listen();
        }
    }

    二、client:

    package org.windwant.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.SocketChannel;
    import java.util.Iterator;
    import java.util.Set;
    
    /**
     * SocketChannel
     */
    public class NIOClient {
        /*标识数字*/
        private static int flag = 0;
        /*缓冲区大小*/
        private static int BLOCK = 4096;
        /*接受数据缓冲区*/
        private static ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);
        /*发送数据缓冲区*/
        private static ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);
        /*服务器端地址*/
        private final static InetSocketAddress SERVER_ADDRESS = new InetSocketAddress(
                "localhost", 8888);
    
        public static void main(String[] args) throws IOException {
            // 打开socket通道
    
            SocketChannel socketChannel = SocketChannel.open();
            // 设置为非阻塞方式
    
            socketChannel.configureBlocking(false);
            // 打开选择器
    
            Selector selector = Selector.open();
            // 注册连接服务端socket动作
    
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            // 连接
    
            socketChannel.connect(SERVER_ADDRESS);
            // 分配缓冲区大小内存
    
    
            Set<SelectionKey> selectionKeys;
            Iterator<SelectionKey> iterator;
            SelectionKey selectionKey;
            SocketChannel client;
            String receiveText;
            String sendText;
            int count=0;
    
            while (true) {
                //选择一组键,其相应的通道已为 I/O 操作准备就绪。
    
                //此方法执行处于阻塞模式的选择操作。
    
                selector.select();
                //返回此选择器的已选择键集。
    
                selectionKeys = selector.selectedKeys();
                //System.out.println(selectionKeys.size());
    
                iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    selectionKey = iterator.next();
                    if (selectionKey.isConnectable()) {
                        System.out.println("client connect");
                        client = (SocketChannel) selectionKey.channel();
                        // 判断此通道上是否正在进行连接操作。
    
                        // 完成套接字通道的连接过程。
    
                        if (client.isConnectionPending()) {
                            client.finishConnect();
                            System.out.println("完成连接!");
                            sendbuffer.clear();
                            sendbuffer.put("Hello,Server".getBytes());
                            sendbuffer.flip();
                            client.write(sendbuffer);
                        }
                        client.register(selector, SelectionKey.OP_READ);
                    } else if (selectionKey.isReadable()) {
                        client = (SocketChannel) selectionKey.channel();
                        //将缓冲区清空以备下次读取
    
                        receivebuffer.clear();
                        //读取服务器发送来的数据到缓冲区中
    
                        count=client.read(receivebuffer);
                        if(count>0){
                            receiveText = new String( receivebuffer.array(),0,count);
                            System.out.println("客户端接受服务器端数据--:"+receiveText);
                            client.register(selector, SelectionKey.OP_WRITE);
                        }
    
                    } else if (selectionKey.isWritable()) {
                        sendbuffer.clear();
                        client = (SocketChannel) selectionKey.channel();
                        sendText = "message from client--" + (flag++);
                        sendbuffer.put(sendText.getBytes());
                        //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
    
                        sendbuffer.flip();
                        client.write(sendbuffer);
                        System.out.println("客户端向服务器端发送数据--:"+sendText);
                        client.register(selector, SelectionKey.OP_READ);
                    }
                }
                selectionKeys.clear();
            }
        }
    }

    项目地址:https://github.com/windwant/windwant-service/tree/master/io-service

  • 相关阅读:
    【spring】【转】Spring 框架的设计理念与设计模式分析
    【ML】贝叶斯估计
    【weka】Use weka in your java code
    【spring】spring的一些思想,哪些bean需要注入
    20130320
    【转】中文分词技术(中文分词原理)
    【ML】【GM】【转】图模型(graphical model, GM)的表示
    【hibernate】【转】Hibernate的一些使用技巧
    20130326
    【orange】【转】orange使用
  • 原文地址:https://www.cnblogs.com/niejunlei/p/5980512.html
Copyright © 2020-2023  润新知