zoukankan      html  css  js  c++  java
  • Nio Server

    package org.fxc.nio.server;
    
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.CharBuffer;
    import java.nio.channels.FileChannel;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    import java.nio.charset.Charset;
    import java.nio.charset.CharsetDecoder;
    import java.util.Iterator;
    
    public class NIOServer {
        static int BLOCK = 500*1024;
    
        /**
         * 处理客户端的内部类,专门负责处理与用户的交互
         */
        public class HandleClient {
            protected FileChannel channel;
            protected ByteBuffer buffer;
            String filePath;
            
             /**
              * 构造函数,文件的管道初始化
              * @param filePath
              * @throws IOException
              */
            public HandleClient(String filePath) throws IOException {
                
                //文件的管道
                this.channel = new FileInputStream(filePath).getChannel();
                
                //建立缓存
                this.buffer = ByteBuffer.allocate(BLOCK);
                this.filePath = filePath;
            }
            
            /**
             * 读取文件管道中数据到缓存中
             * @return
             */
            public ByteBuffer readBlock() {
                try {
                    
                    //清除缓冲区的内容,posistion设置为0,limit设置为缓冲的容量大小capacity
                    buffer.clear();
                    
                    //读取
                    int count = channel.read(buffer);
                    
                    //将缓存的中的posistion设置为0,将缓存中的limit设置在原始posistion位置上
                    buffer.flip();
                    if (count <= 0)
                        return null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return buffer;
            }
            
            /**
             * 关闭服务端的文件管道
             */
            public void close() {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        protected Selector selector;
        protected String filename = "d:\film\hadoop-1.1.2.tar.gz"; // a big file
        protected ByteBuffer clientBuffer = ByteBuffer.allocate(BLOCK);
        protected CharsetDecoder decoder;
        
        //构造服务端口,服务管道等等
        public NIOServer(int port) throws IOException {
            selector = this.getSelector(port);
            Charset charset = Charset.forName("GB2312");
            decoder = charset.newDecoder();
        }
    
        // 获取Selector
        //构造服务端口,服务管道等等
        protected Selector getSelector(int port) throws IOException {
            ServerSocketChannel server = ServerSocketChannel.open();
            Selector sel = Selector.open();
            server.socket().bind(new InetSocketAddress(port));
            server.configureBlocking(false);
            
            //刚开始就注册链接事件
            server.register(sel, SelectionKey.OP_ACCEPT);
            return sel;
        }
    
        // 服务启动的开始入口
        public void listen() {
            try {
                for (;;) {                
                    //
                    selector.select();
                    Iterator<SelectionKey> iter = selector.selectedKeys()
                            .iterator();
                    while (iter.hasNext()) {//首先是最先感兴趣的连接事件
                        SelectionKey key = iter.next();                    
                        //
                        iter.remove();
                        
                        //处理事件
                        handleKey(key);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        // 处理事件
        protected void handleKey(SelectionKey key) throws IOException {
            if (key.isAcceptable()) { // 接收请求
                
                //允许网络连接事件
                ServerSocketChannel server = (ServerSocketChannel) key.channel();
                SocketChannel channel = server.accept();
                channel.configureBlocking(false);
                
                //网络管道准备处理读事件
                channel.register(selector, SelectionKey.OP_READ);
            } else if (key.isReadable()) { // 读信息
                SocketChannel channel = (SocketChannel) key.channel();
                
                //从客户端读过来的数据块
                int count = channel.read(clientBuffer);
                if (count > 0) {
                    
                    //读取过来的缓存进行有效分割,posistion设置为0,保证从缓存的有效位置开始读取,limit设置为原先的posistion上
                    //这样一来从posistion~limit这段缓存数据是有效,可利用的
                    clientBuffer.flip();
                    
                    //对客户端缓存块进行编码
                    CharBuffer charBuffer = decoder.decode(clientBuffer);
                    System.out.println("Client >>download>>" + charBuffer.toString());
                    
                    //对网络管道注册写事件
                    SelectionKey wKey = channel.register(selector,
                            SelectionKey.OP_WRITE);
                    
                    //将网络管道附着上一个处理类HandleClient,用于处理客户端事件的类
                    wKey.attach(new HandleClient(charBuffer.toString()));
                } else{
                    //如客户端没有可读事件,关闭管道
                    channel.close();
                }
                    
                clientBuffer.clear();
            } else if (key.isWritable()) { // 写事件
                SocketChannel channel = (SocketChannel) key.channel();
                
                //从管道中将附着处理类对象HandleClient取出来
                HandleClient handle = (HandleClient) key.attachment();
                
                //读取文件管道,返回数据缓存
                ByteBuffer block = handle.readBlock();
                if (block != null){
                    //System.out.println("---"+new String(block.array()));
                    
                    //写给客户端
                    channel.write(block);
                }else {
                    handle.close();
                    channel.close();
                }
            }
        }
    
        public static void main(String[] args) {
            int port = 12345;
            try {
                NIOServer server = new NIOServer(port);
                System.out.println("Listernint on " + port);
                while (true) {
                    server.listen();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • 相关阅读:
    less本地环境输出hello-world
    HTML中的SEO和HTML语义化
    JS连等赋值的坑
    React官网首页demo(单文件实现版)
    高并发高可用的架构实践-静态架构蓝图(二)
    高并发高可用的架构实践-设计理念(一)
    云计算+区块链=BaaS
    001/Nginx高可用模式下的负载均衡与动静分离(笔记)
    001---mysql分库分表
    004--PowerDesigner设置显示1对多等关系
  • 原文地址:https://www.cnblogs.com/fuxinci/p/3201889.html
Copyright © 2011-2022 走看看