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();
            }
        }
    }
}
原文地址:https://www.cnblogs.com/shugen/p/6863000.html