文档章节

nio服务器端

marjey
 marjey
发布于 2016/12/12 14:31
字数 1038
阅读 9
收藏 0

使用异步处理IO的方式,使用一个线程,处理大量的链接。

先对NIO原理和通信模型做一些了解。

1. 由一个专门的线程来处理所有的 IO 事件,并负责分发。 
2. 事件驱动机制:事件到的时候触发,而不是同步的去监视事件。 
3. 线程通讯:线程之间通过 wait,notify 等方式通讯。保证每次上下文切换都是有意义的。减少无谓的线程切换。 

Java NIO的服务端只需启动一个专门的线程来处理所有的 IO 事件,这种通信模型是怎么实现的呢?呵呵,我们一起来探究它的奥秘吧。java NIO采用了双向通道(channel)进行数据传输,而不是单向的流(stream),在通道上可以注册我们感兴趣的事件。一共有以下四种事件:

 

事件名 对应值
服务端接收客户端连接事件 SelectionKey.OP_ACCEPT(16)
客户端连接服务端事件 SelectionKey.OP_CONNECT(8)
读事件 SelectionKey.OP_READ(1)
写事件 SelectionKey.OP_WRITE(4)

服务端和客户端各自维护一个管理通道的对象,我们称之为selector,该对象能检测一个或多个通道 (channel) 上的事件。我们以服务端为例,如果服务端的selector上注册了读事件,某时刻客户端给服务端发送了一些数据,阻塞I/O这时会调用read()方法阻塞地读取数据,而NIO的服务端会在selector中添加一个读事件。服务端的处理线程会轮询地访问selector,如果访问selector时发现有感兴趣的事件到达,则处理这些事件,如果没有感兴趣的事件到达,则处理线程会一直阻塞直到感兴趣的事件到达为止。下面是我理解的java NIO的通信模型示意图:

package priv.lee.paradise.nioserver.listen;


import priv.lee.paradise.nioserver.distribute.DoGetOperater;
import priv.lee.paradise.nioserver.distribute.DoPostOperater;
import priv.lee.paradise.nioserver.util.SocketUtil;

import java.nio.channels.SocketChannel;

/**
 * Created by li on 2016/12/12.
 * 当所监听的端口有连接进来的时候,可通过端口监听器通知观察者进行下一步操作。
 */
class ListenerObserver {

    /**
     * 当有新连接进来的时候,会通知该类调用静态方法。
     * 每传入一个新的socketChannel会新建一个线程对其进行处理。
     *
     * @param socketChannel 客户端和服务器的嵌套字。
     */
    static void acceptNotify(SocketChannel socketChannel) {
        String requestInfo = SocketUtil.getRequest(socketChannel);
        System.out.println(requestInfo);
        if (requestInfo.contains("GET")) {
            DoGetOperater doGetOperater = new DoGetOperater(socketChannel, requestInfo);
            doGetOperater.doGet();
        }
        if (requestInfo.contains("POST")) {
            DoPostOperater doPostOperater = new DoPostOperater(requestInfo, socketChannel);
            doPostOperater.doPost();
        }
    }
}
package priv.lee.paradise.nioserver.listen;

import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * Created by li on 2016/12/11.
 * 使用nio创建的端口监听器。本类不再使用静态方法。
 */
public class PortListener {
    private int port;
    private Selector selector;

    /**
     * 初始化监听器,要创建监听器必须传入端口号
     * param:port 端口号。
     * return:null
     */
    public PortListener(int port) {
        this.port = port;
        init();
    }

    /**
     * 初始化端口监听器,获取通道、注册事件。
     * param:null;
     * return:null
     */
    private void init() {
        ServerSocketChannel serverSocketChannel = getServerSocketChannel();
        selector = getSelector();
        registerEvent(serverSocketChannel, selector, SelectionKey.OP_ACCEPT);

    }

    /**
     * 开始监听事件。
     */
    public void startListening() {
        System.out.println("开始监听" + port + "号端口");
        while (!Thread.interrupted()) {
            handleEvent();
        }
    }

    /**
     * 但监听器监听到注册过的事件到来的时候,
     * selector.select();为线程阻塞方法,当感兴趣的事件到来的时候才会触发这个方法。
     */
    private void handleEvent() {
        try {
            selector.select();
            Iterator iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = (SelectionKey) iterator.next();
                if (key.isAcceptable()) {
                    handleAcceptableEvent(key);
                } else if (key.isReadable()) {
                    handleReadableEvent(key);
                }
                iterator.remove();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 处理一个可读的事件。
     *
     * @param key 可读事件
     */
    private void handleReadableEvent(SelectionKey key) {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        ListenerObserver.acceptNotify(socketChannel);



    }


    /**
     * 处理Acceptable事件
     *
     * @param key 以注册是的事件触发。并向选择器注册读取事件。
     */
    private void handleAcceptableEvent(SelectionKey key) {
        ServerSocketChannel serverSocketChannel;
        try {
            serverSocketChannel = (ServerSocketChannel) key.channel();
            SocketChannel socketChannel = serverSocketChannel.accept();
            socketChannel.configureBlocking(false);
            socketChannel.register(selector, SelectionKey.OP_READ);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取一个ServerSocketChannel对象,并对其进行一些配置。
     * param:null。
     * return:ServerSocketChannel
     */

    private ServerSocketChannel getServerSocketChannel() {
        ServerSocketChannel serverSocketChannel = null;
        try {
            serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.socket().bind(new InetSocketAddress(port));

        } catch (Exception e) {
            e.printStackTrace();

        }
        return serverSocketChannel;
    }

    /**
     * 获取一个选择器。
     * param:null
     * return Selector.
     */

    private Selector getSelector() {
        Selector selector = null;
        try {
            selector = Selector.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return selector;
    }

    /**
     * 为通道注册选择器要监听的事件。
     *
     * @param serverSocketChannel 待监测的通道。
     * @param selector            选择器
     * @param opAccept            待监听的事件选项(int)。
     */


    private void registerEvent(ServerSocketChannel serverSocketChannel, Selector selector, int opAccept) {
        try {
            serverSocketChannel.register(selector, opAccept);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

© 著作权归作者所有

共有 人打赏支持
marjey
粉丝 3
博文 173
码字总数 139219
作品 0
昆明
私信 提问
使用Nginx代理thrift NIO实现SSL链路加密

1 目标说明 1.1 调研目的 本次调研主要为了解决两个问题: thrift提供的SSL API只支持BIO(阻塞式IO),而我们使用的是NIO API,希望能在不改变IO模型的前提下对链路进行加密; 未来系统可能...

囚兔
2016/06/22
2.9K
11
JAVA NIO non-blocking模式实现高并发服务器

Java自1.4以后,加入了新IO特性,NIO. 号称new IO. NIO带来了non-blocking特性. 这篇文章主要讲的是如何使用NIO的网络新特性,来构建高性能非阻塞并发服务器. 文章基于个人理解,我也来搞搞NIO.,...

Mr&Cheng
2013/01/30
0
1
JAVA NIO non-blocking模式实现高并发服务器

Java自1.4以后,加入了新IO特性,NIO. 号称new IO. NIO带来了non-blocking特性. 这篇文章主要讲的是如何使用NIO的网络新特性,来构建高性能非阻塞并发服务器. 文章基于个人理解,我也来搞搞NIO.,...

xpbug
2013/01/10
0
4
Java NIO 高性能服务器编程

最近在研究如何使用NIO技术开发一个多用户在线的即时通讯工具,如题,请问各位大神: 1、如何架构服务器端设计能够增加系统的吞吐量和效率呢? 2、即时通讯过程中非常常见的就是客户端A发送信...

passenger
2014/09/19
1K
7
关于BIO和NIO的理解

最近大概看了ZooKeeper和Mina的源码发现都是用Java NIO实现的,所以有必要搞清楚什么是NIO。下面是我结合网络资料自己总结的,为了节约时间图示随便画的,能达意就行。 简介:BIO:同步阻塞式...

天天顺利
2015/10/23
7.3K
0

没有更多内容

加载失败,请刷新页面

加载更多

PHP生成CSV之内部换行

当我们使用PHP将采集到的文件内容保存到csv文件时,往往需要将采集内容进行二次过滤处理才能得到需要的内容。比如网页中的换行符,空格符等等。 对于空格等处理起来都比较简单,这里我们单独...

豆花饭烧土豆
今天
1
0
使用 mjml 生成 thymeleaf 邮件框架模板

发邮件算是系统开发的一个基本需求了,不过搞邮件模板实在是件恶心事,估计搞过的同仁都有体会。 得支持多种客户端 支持响应式 疼彻心扉的 outlook 多数客户端只支持 inline 形式的 css 布局...

郁也风
今天
4
0
让哲学照亮我们的人生——读《医务工作者需要学点哲学》有感2600字

让哲学照亮我们的人生——读《医务工作者需要学点哲学》有感2600字: 作者:孙冬梅;以前读韩国前总统朴槿惠的著作《绝望锻炼了我》时,里面有一句话令我印象深刻,她说“在我最困难的时期,...

原创小博客
今天
4
0
JAVA-四元数类

public class Quaternion { private final double x0, x1, x2, x3; // 四元数构造函数 public Quaternion(double x0, double x1, double x2, double x3) { this.x0 = ......

Pulsar-V
今天
17
0
Xshell利用Xftp传输文件,使用pure-ftpd搭建ftp服务

Xftp传输文件 如果已经通过Xshell登录到服务器,此时可以使用快捷键ctrl+alt+f 打开Xftp并展示Xshell当前的目录,之后直接拖拽传输文件即可。 pure-ftpd搭建ftp服务 pure-ftpd要比vsftp简单,...

野雪球
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部