• 学习 java netty (一) -- java nio


    前言:近期在研究java netty这个网络框架,第一篇先介绍java的nio。


    java nio在jdk1.4引入,事实上也算比較早的了。主要引入非堵塞io和io多路复用。内部基于reactor模式。


    nio核心:
    - buffer
    - channel
    - selector

    buffer:
    相似网络编程中的缓冲区,有
    ByteBuffer 字节
    CharBuffer 字符
    IntBuffer
    DoubleBuffer…
    经常使用的有ByteBuffer和CharBuffer

    java nio buffer是开辟了一块空间。内部有4个标记,分别为position,limit。capicity。mask。
    这里写图片描写叙述
    position是当前读缓冲区位置,limit是数据的结尾。表示最多能读到limit位置,capacity是缓冲区的容量。在position和limit之间还会有mask用来标记一个位置,能够移动position到达mask位置
    buffer有两个重要的方法clear和flip
    clear()方法没有清空数据而是将position置为0,limit置为capacity,
    为再次向buffer装数据做好准备
    flip()方法在装载完数据后。将limit设为当前position位置,然后将position设置为0,简单来说就是flip()为从buffer中取出数据做好准备。


    >

    channel:
    相似网络编程中的套接字,Java nio中称为Channel(通道),个人觉得这样更加方便我们理解,服务器和客户端之间通过Channel来数据传输。
    channel 有
    FileChannel 文件管道
    DatagramChannel 数据报管道
    SocketChannel socket管道
    ServerSocketChannel 服务端socket管道
    channel能够直接文件的部分或所有映射为buffer
    注意:
    程序不能直接訪问channel的数据。channel必须和buffer结合起来使用。
    所有的channel都不应该用构造器,从传统的流节点Inputstream 等来获取channel


    selector:
    事件分发收集器,内部封装的epoll。我们能够往上面注冊事件,然后监听多个channel通道上的事件等。


    时序图
    nio时序图
    注:图片非原创

    从时序图能够看出java nio和我们平时写的网络编程非常像。


    java nio实现简单的回射服务器

    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.*;
    import java.nio.channels.spi.SelectorProvider;
    import java.nio.charset.Charset;
    import java.util.Set;
    
    /**
     * Created by wwh on 15-7-25.
     */
    public class NioSocket {
        //字符序列和字节序列的编码和解码
        private Charset charset = Charset.forName("UTF-8");
    
        void run(String ip, int port) throws IOException {
            try {
                //创建服务端套接字
                ServerSocketChannel server = ServerSocketChannel.open();
                //绑定ip和端口
                server.socket().bind(new InetSocketAddress(ip, port));
                //设置非堵塞
                server.configureBlocking(false);
                //创建selector事件选择器
                Selector selector = Selector.open();
                //将自己的监听套接字注冊到selector上。监听 accept事件
                //SelectionKey代表SelectableChannel和Selector的关系。Selectable是Selector可监听的事件channel.
                server.register(selector, SelectionKey.OP_ACCEPT);
                while(selector.select() > 0){
                    //selector.select()返回事件
                    for(SelectionKey sk : selector.selectedKeys()) {
                        //从事件集合中删除正要处理的事件
                        selector.selectedKeys().remove(sk);
                        //推断事件的类型,依次处理
                        if(sk.isAcceptable()){
                            //假设事件为接受连接accpet事件
                            System.out.println("accpet 事件");
                            //调用accept接受请求连接
                            SocketChannel client = server.accept();
                            //设置为非堵塞
                            client.configureBlocking(false);
                            //向selector上注冊读事件
                            client.register(selector, SelectionKey.OP_READ);
                            //将sk相应的channel设置为准备接受其它请求
                            sk.interestOps(SelectionKey.OP_ACCEPT);
                        }
                        if(sk.isReadable()){
                            //假设事件为可读事件
                            System.out.println("read 事件");
                            SocketChannel client = (SocketChannel)sk.channel();
                            //定义缓冲区
                            ByteBuffer buffer = ByteBuffer.allocate(1024);
                            String mesg = "";
                            try {
                                while (client.read(buffer) > 0) {
                                    buffer.flip();
                                    mesg += charset.decode(buffer);
                                }
                                System.out.println("收到:" + mesg);
                                sk.interestOps(SelectionKey.OP_READ);
                            }catch (IOException e){
                                //假设出现异常,则取消当前的client连接
                                sk.cancel();
                                if(sk.channel() != null){
                                    sk.channel().close();
                                }
                            }
                            //回复给发来消息的client
                            client.write(charset.encode(mesg));
                            System.out.println("回复:" + mesg);
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) throws IOException {
            NioSocket Server = new NioSocket();
            Server.run("192.168.10.75", 10000);
        }
    }
  • 相关阅读:
    JS实现图片预加载无需等待
    对网页渲染的初步认识
    没人告诉你关于z-index的一些事
    使用CSS3的appearance属性改变元素的外观
    js+css立体旋转
    css3立体旋转动画
    炫酷的jquery瀑布流
    基于jquery的图片懒加载js
    transform应用详解
    css3+js打造炫酷图片展示
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/7136211.html
Copyright © 2020-2023  润新知