java reactor 模式_Java NIO之Reactor模式

Java NIO之Reactor模式

如下图所示,

4e75274840dc899ad6f3b3d79ea443a3.png

Single Threaded Versioin指的是 Reactor 只有一个线程在处理 IO 事件,分发所有的IO事件,而具体的处理过程则是由Handler 去做。

那么一个Reactor系统只有一个Reactor,如果有100 个连接,那么就有100 个Handler 在处理。(看下面代码)

7a5b15e3da7be2b58ab4805106568eaf.png

我就按我的理解说一下一次网络请求的过程:

1.如下面Reactor的构造方法,启动一个Reactor系统。

public Reactor(int port) throws IOException {

selector = Selector.open();

serverSocket = ServerSocketChannel.open();

serverSocket.socket().bind(

new InetSocketAddress(port));

serverSocket.configureBlocking(false);

SelectionKey sk =

serverSocket.register(selector,

SelectionKey.OP_ACCEPT);

//利用sk的attache功能绑定Acceptor 如果有事情,触发Acceptor

sk.attach(new Acceptor());

log.info("->attach(new Acceptor())");

}

启动的时候把当前的 serverSocket 注册到给定的selector,并且指明感兴趣的事件,SelectionKey.OP_ACCEPT,然后返回一个SelectionKey,这个key表示当前的channel 和 selector的映射关系。

2.如果现在有一个网络连接,如果网络的OP_ACCEPT事件发生,则调用selector.selectedKeys();会得到一个关于OP_ACCEPT事件的key,然后dispatch(sk);分发这个事件。通过key的attachment()方法得到附加的对象,这个对象是一个线程对象,也是Acceptor对象。在这里处理网络连接,得到客户端的socketchannel。

3.得到了客户端的socketchannel,就可以准备读写客户端的socketchannel了。先注册一个SelectionKey.OP_READ读事件。并且当前的Handler对象附加到key对象上sk.attach(this);。

MulitiHandler(Selector selector, SocketChannel c) throws IOException {

socket = c;

c.configureBlocking(false);

// Optionally try first read now

sk = socket.register(selector, 0);

// 注意在Handler里面又执行了一次attach,这样,覆盖前面的Acceptor,

// 下次该Handler又有READ事件发生时,

// 将直接触发Handler.从而开始了数据的读->处理->写->发出等流程处理。

sk.attach(this);

sk.interestOps(SelectionKey.OP_READ);

selector.wakeup();

}

4.当READ事件发生后,则会通过dispatch(sk);分发。通过Handler的run方法进行具体的IO的读操作。

5.读完了数据之后,注册OP_WRITE事件sk.interestOps(SelectionKey.OP_WRITE)。然后当该事件发生后,则分发该事件,调用Handler的run事件处理IO写操作。

如下代码示例,

package com.usoft;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.io.IOException;

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;

import java.util.Set;

public class Reactor implements Runnable {

private static Logger log = LoggerFactory.getLogger(Reactor.class);

final Selector selector;

final ServerSocketChannel serverSocket;

public Reactor(int port) throws IOException {

selector = Selector.open();

serverSocket = ServerSocketChannel.open();

serverSocket.socket().bind(

new InetSocketAddress(port));

serverSocket.configureBlocking(false);

SelectionKey sk =

serverSocket.register(selector,

SelectionKey.OP_ACCEPT);

//利用sk的attache功能绑定Acceptor 如果有事情,触发Acceptor

sk.attach(new Acceptor());

log.info("->attach(new Acceptor())");

}

// Alternatively,use explicit SPI provider :

// SelectorProvider p = SelectorProvider.provider();

// selector=p.openSelector();

// serverSocket=p.openServerSocketChannel();

// class Reactor continued

public void run() { // normally in a new Thread

try {

while (!Thread.interrupted()) {

selector.select();

Set selected = selector.selectedKeys();

Iterator it = selected.iterator();

//Selector如果发现channel有OP_ACCEPT或READ事件发生,下列遍历就会进行。

while (it.hasNext()) {

//来一个事件 第一次触发一个accepter线程

//以后触发Handler

SelectionKey sk = (SelectionKey) it.next();

log.info(">>>>>>acceptable=" + sk.isAcceptable() +

",readable=" + sk.isReadable() +

",writable=" + sk.isWritable());

dispatch(sk);

}

selected.clear();

}

} catch (IOException ex) {

log.info("reactor stop!" + ex);

}

}

void dispatch(SelectionKey k) {

Runnable r = (Runnable) (k.attachment());

if (r != null) {

r.run();

}

}

// class Reactor continued

class Acceptor implements Runnable { // inner

public void run() {

try {

log.debug("-->ready for accept!");

SocketChannel c = serverSocket.accept();

if (c != null)

new Handler(selector, c);

} catch (IOException ex) { /* . . . */ }

}

}

}

package com.usoft;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.io.IOException;

import java.nio.ByteBuffer;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.SocketChannel;

final class Handler implements Runnable {

private static Logger log = LoggerFactory.getLogger(Reactor.class);

static final int MAXIN = 1024;

static final int MAXOUT = 1024;

final SocketChannel socket;

final SelectionKey sk;

ByteBuffer input = ByteBuffer.allocate(MAXIN);

ByteBuffer output = ByteBuffer.allocate(MAXOUT);

static final int READING = 0, SENDING = 1;

int state = READING;

Handler(Selector selector, SocketChannel c) throws IOException {

socket = c;

c.configureBlocking(false);

// Optionally try first read now

sk = socket.register(selector, 0);

// 注意在Handler里面又执行了一次attach,这样,覆盖前面的Acceptor,

// 下次该Handler又有READ事件发生时,

// 将直接触发Handler.从而开始了数据的读->处理->写->发出等流程处理。

sk.attach(this);

sk.interestOps(SelectionKey.OP_READ);

selector.wakeup();

}

boolean inputIsComplete() {

return true; //只是返回true,具体的判断没有实现

}

boolean outputIsComplete() {

return true;//只是返回true,具体的判断没有实现

}

void process() { //没有具体实现

output.put("helloworld".getBytes());

}

// class Handler continued

public void run() {

try {

if (state == READING) read();

else if (state == SENDING) send();

} catch (IOException ex) { /* . . . */ }

}

void read() throws IOException {

log.info("->read into bytebuffer from socketchannel inputs");

socket.read(input);

if (inputIsComplete()) {

log.info("->read complete");

process();

state = SENDING;

// Normally also do first write now

// 读完了数据之后,注册OP_WRITE事件

sk.interestOps(SelectionKey.OP_WRITE);

}

}

void send() throws IOException {

log.info("->write into socketchannel from bytebuffer outputs");

socket.write(output);

if (outputIsComplete()) {

/**

* The key will be removed fromall of the selector's key sets

* during the next selection operation.

*/

sk.cancel();

socket.close(); //关闭通过,也就关闭了连接

log.info("->close socketchannel after write complete");

}

}

}

ReactorTest.java

package com.usoft;

import java.io.IOException;

/**

* Created by liyanxin on 2015/3/23.

*/

public class ReactorTest {

public static void main(String args[]) throws IOException {

Reactor reactor = new Reactor(9098);

reactor.run();

}

}

=============END=============

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值