• NioSocket相关知识


    一、Nio简介

    nio 是non-blocking的简称,在jdk1.4 里提供的新api 。Sun 官方标榜的特性如下: 为所有的原始类型提供(Buffer)缓存支持。字符集编码解码解决方案。 Channel :一个新的原始I/O 抽象。 支持锁和内存映射文件的文件访问接口。 提供多路(non-bloking) 非阻塞式的高伸缩性网络I/O 。

    java.nio包是Java在1.4之后增加的,用来提高I/O操作的效率。在nio包中主要包括以下几个类或接口:

    * Buffer:缓冲区,用来临时存放输入或输出数据。
    * Charset:用来把Unicode字符编码和其它字符编码互转。
    * Channel:数据传输通道,用来把Buffer中的数据写入到数据源,或者把数据源中的数据读入到Buffer。
    * Selector:用来支持异步I/O操作,也叫非阻塞I/O操作。
    

    nio包中主要通过下面两个方面来提高I/O操作效率:

    * 通过Buffer和Channel来提高I/O操作的速度。
    * 通过Selector来支持非阻塞I/O操作。
    

    传送门:NIO与IO的区别

    二、NioSocket

    NIO为socket提供了新的连接方式。使用NioSocket的流程如下:

    Created with Raphaël 2.1.0开始建立ServerSocketChannel设置相应的参数。创建Selector并注册到ServerSocketChannel上。调用Selector的select方法等待请求,可以制定超时时间。Selector接收到请求后使用selectedKeys返回SelectionKey集合。使用SelectionKey获取到Channel、Selector和操作类型并进行具体的操作。结束

    三、服务器示例代码

    package com.frank.java.util;
    
    /**
     * Created by Administrator on 2016/6/24.
     */
    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.nio.charset.Charset;
    import java.util.Iterator;
    
    public class NIOServer {
        public static void main(String[] args) throws Exception{
            //创建ServerSocketChannel,监听8080端口
            ServerSocketChannel ssc=ServerSocketChannel.open();
            ssc.socket().bind(new InetSocketAddress(8081));
            //设置为非阻塞模式
            ssc.configureBlocking(false);
            //为ssc注册选择器
            Selector selector=Selector.open();
            ssc.register(selector, SelectionKey.OP_ACCEPT);
            //创建处理器
            Handler handler = new Handler(1024);
            while(true){
                // 等待请求,每次等待阻塞3s,超过3s后线程继续向下运行,如果传入0或者不传参数将一直阻塞
                if(selector.select(3000)==0){
                    System.out.println("等待请求超时。。。");
                    continue;
                }
                System.out.println("处理请求。。。");
                // 获取待处理的SelectionKey
                Iterator<SelectionKey> keyIter=selector.selectedKeys().iterator();
    
                while(keyIter.hasNext()){
                    SelectionKey key=keyIter.next();
                    try{
                        // 接收到连接请求时
                        if(key.isAcceptable()){
                            handler.handleAccept(key);
                        }
                        // 读数据
                        if(key.isReadable()){
                            handler.handleRead(key);
                        }
                    } catch(IOException ex) {
                        keyIter.remove();
                        continue;
                    }
                    // 处理完后,从待处理的SelectionKey迭代器中移除当前所使用的key
                    keyIter.remove();
                }
            }
        }
    
        private static class Handler {
            private int bufferSize = 1024;
            private String  localCharset = "UTF-8";
    
            public Handler(){}
            public Handler(int bufferSize){
                this(bufferSize, null);
            }
            public Handler(String  LocalCharset){
                this(-1, LocalCharset);
            }
            public Handler(int bufferSize, String  localCharset){
                if(bufferSize>0)
                    this.bufferSize=bufferSize;
                if(localCharset!=null)
                    this.localCharset=localCharset;
            }
    
            public void handleAccept(SelectionKey key) throws IOException {
                SocketChannel sc=((ServerSocketChannel)key.channel()).accept();
                sc.configureBlocking(false);
                sc.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
            }
    
            public void handleRead(SelectionKey key) throws IOException {
                // 获取channel
                SocketChannel sc=(SocketChannel)key.channel();
                // 获取buffer并重置
                ByteBuffer buffer=(ByteBuffer)key.attachment();
                buffer.clear();
                // 没有读到内容则关闭
                if(sc.read(buffer)==-1){
                    sc.close();
                } else {
                    // 将buffer转换为读状态
                    buffer.flip();
                    // 将buffer中接收到的值按localCharset格式编码后保存到receivedString
                    String receivedString =                Charset.forName(localCharset).newDecoder().decode(buffer).toString();
                    System.out.println("received from client: " + receivedString);
    
                    // 返回数据给客户端
                    String sendString = "received data: " + receivedString;
                    buffer = ByteBuffer.wrap(sendString.getBytes(localCharset));
                    sc.write(buffer);
                    // 关闭Socket
                    sc.close();
                }
            }
        }
    }
  • 相关阅读:
    JavaScript在Javascript中为String对象添加trim,ltrim,rtrim方法
    JavaScriptjs写的俄罗斯方块
    WinForm中“嵌入的资源”和“资源文件”数据的获取方式
    Facade模式(外观模式)
    windows服务安装程序中如何安装后自动启动
    水晶报表之主从多表数据源批量预览及打印开发设计
    IP地址分类简介
    水晶报表之各节的作用
    水晶报表开发之常用代码以及注意事项
    .Net中后台线程和前台线程的区别
  • 原文地址:https://www.cnblogs.com/shugen/p/6863000.html
Copyright © 2020-2023  润新知