网络编程 -- RPC实现原理 -- 目录

  啦啦啦

V2——增加WriteQueue队列,存放selectionKey。addWriteEventToQueue()添加selectionKey并唤醒阻塞的selector。等selector唤醒之后再注册OP_WRITE事件。

selectionKey.cancel();清除key对应事件之后,由于多线程 main线程和对应的IO线程会抢夺selector资源。

在selector.select()和sc.register(selectionKey.selector(), SelectionKey.OP_WRITE);处会发生死锁,因此将需要注册IO操作的selectionKey放入队列并唤醒selector,之后在注册IO操作。

NIO 多线程

1.打开Selector
2.打开ServerSocketChannel
3.获取与此Channel关联的ServerSocket并绑定地址
4.设置Channel为非阻塞
5.将Channel注册到Selector并指定操作位

6.阻塞select()返回具有操作的通道个数。如果唤醒之后就绪通道数小于1,则将WriteQueue、ReadQueue队列中的所有sc注册到selector中并分别设置写操作位、读操作位。
7.获取SelectionKeys遍历,最后移除
8.根据key判断操作:isAcceptable、isConnectable、isReadable、isWritable
9.1.isAcceptable:根据key获取Channel,accept()获取SocketChannel并设置为非阻塞模式,注册到Selector并指定读操作位和缓冲区。
9.2.isConnectable:仅仅就是连接状态
9.3.isReadable:取消Read事件,启动Read线程处理IO读操作。添加selectionKey到WriteQueue中并唤醒selector。
9.4.isWritable:取消Write事件,启动Write线程处理IO写操作。添加selectionKey到ReadQueue中并唤醒selector。

    private static Queue<SelectionKey> writeQueue = new LinkedBlockingQueue<SelectionKey>();
public static void addWriteEventToQueue(SelectionKey selectionKey) {
System.out.println(Thread.currentThread() + " -- -- -- 添加selectionKey到队列,并唤醒selector");
writeQueue.add(selectionKey);
selectionKey.selector().wakeup();
}
       int n = selector.select();
System.out.println(Thread.currentThread() + " 事件就绪通道个数 : " + n);
if(n < 1){
System.out.println(Thread.currentThread() + " -- -- -- selector被唤醒,注册队列中所有socketChannel为OP_WRITE操作");
Iterator<SelectionKey> iterator = writeQueue.iterator();
while(iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
SocketChannel sc = (SocketChannel) selectionKey.channel();
sc.register(selectionKey.selector(), SelectionKey.OP_WRITE);
}
}

  Class : Service

package lime.pri.limeNio.optimize.socket4;

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.Queue;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue; public class Service { public static void main(String[] args) throws IOException, InterruptedException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(9999));
serverSocketChannel.configureBlocking(false);
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
System.out.println(Thread.currentThread() + " 监听端口@9999,等待客户端连接...");
int n = selector.select();
System.out.println(Thread.currentThread() + " 事件就绪通道个数 : " + n);
if(n < 1){
System.out.println(Thread.currentThread() + " -- -- -- selector被唤醒,注册队列中所有socketChannel为OP_WRITE操作");
Iterator<SelectionKey> iterator = writeQueue.iterator();
while(iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
SocketChannel sc = (SocketChannel) selectionKey.channel();
sc.register(selectionKey.selector(), SelectionKey.OP_WRITE);
}
}
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
iterator.remove();
if (selectionKey.isValid() && selectionKey.isAcceptable()) {
System.out.println(Thread.currentThread() + " -- -- -- 处理Acceptable事件");
ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
}
if (selectionKey.isValid() && selectionKey.isReadable()) {
System.out.println(Thread.currentThread() + " -- -- -- 处理Readable事件");
selectionKey.cancel();
RequestProcessor.proceess(selectionKey, selector);
}
if (selectionKey.isValid() && selectionKey.isWritable()) {
System.out.println(Thread.currentThread() + " -- -- -- 处理Writable事件");
selectionKey.cancel();
ResponseProcessor.proceess(selectionKey, selector);
}
}
}
} private static Queue<SelectionKey> writeQueue = new LinkedBlockingQueue<SelectionKey>();
public static void addWriteEventToQueue(SelectionKey selectionKey) {
System.out.println(Thread.currentThread() + " -- -- -- 添加selectionKey到队列,并唤醒selector");
writeQueue.add(selectionKey);
selectionKey.selector().wakeup();
}
}

  Class : RequestProcessor

package lime.pri.limeNio.optimize.socket4;

import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class RequestProcessor { private static ExecutorService exec = Executors.newFixedThreadPool(2); public static void proceess(final SelectionKey selectionKey, final Selector selector) {
exec.submit(new Runnable() { public void run() {
try {
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
byteBuffer.clear();
SocketChannel sc = (SocketChannel) selectionKey.channel();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while(sc.read(byteBuffer) != -1){
bos.write(byteBuffer.array());
byteBuffer.clear();
}
System.out.println(Thread.currentThread() + " 客户端( " + sc.getRemoteAddress() + " ) 请求 : " + bos.toString());
Service.addWriteEventToQueue(selectionKey);
} catch (Exception e) {
}
}
});
} }

  Class : ResponseProcessor

package lime.pri.limeNio.optimize.socket4;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class ResponseProcessor { private static ExecutorService exec = Executors.newFixedThreadPool(2); public static void proceess(final SelectionKey selectionKey, final Selector selector) {
exec.submit(new Runnable() { public void run() {
try {
String response = "服务端响应 : " + new Date().toString();
ByteBuffer byteBuffer = ByteBuffer.wrap(response.getBytes());
SocketChannel sc = (SocketChannel) selectionKey.channel();
sc.write(byteBuffer);
sc.close();
} catch (IOException e) {
}
}
});
} }

  Class : Client

package lime.pri.limeNio.optimize.socket4;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; public class Client { public static void main(String[] args) throws IOException {
for (int i = 0; i < 10; i++) {
new Thread() {
@Override
public void run() {
try {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999)); socketChannel.write(ByteBuffer.wrap("Query Date".getBytes()));
socketChannel.shutdownOutput(); ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socketChannel.read(byteBuffer);
System.out.println(new String(byteBuffer.array()));
socketChannel.close();
} catch (IOException e) {
}
} }.start();
}
}
}

  Console: Server

Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 1
Thread[main,5,main] -- -- -- 处理Acceptable事件
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 1
Thread[main,5,main] -- -- -- 处理Acceptable事件
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 3
Thread[main,5,main] -- -- -- 处理Acceptable事件
Thread[main,5,main] -- -- -- 处理Readable事件
Thread[main,5,main] -- -- -- 处理Readable事件
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 2
Thread[main,5,main] -- -- -- 处理Acceptable事件
Thread[main,5,main] -- -- -- 处理Readable事件
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 2
Thread[main,5,main] -- -- -- 处理Readable事件
Thread[main,5,main] -- -- -- 处理Acceptable事件
Thread[pool-1-thread-2,5,main] 客户端( /127.0.0.1:4643 ) 请求 : Query Date
Thread[pool-1-thread-2,5,main] -- -- -- 添加selectionKey到队列,并唤醒selector
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 2
Thread[main,5,main] -- -- -- 处理Readable事件
Thread[main,5,main] -- -- -- 处理Acceptable事件
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 2
Thread[main,5,main] -- -- -- 处理Readable事件
Thread[main,5,main] -- -- -- 处理Acceptable事件
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 2
Thread[main,5,main] -- -- -- 处理Acceptable事件
Thread[pool-1-thread-2,5,main] 客户端( /127.0.0.1:4645 ) 请求 : Query Date
Thread[main,5,main] -- -- -- 处理Readable事件
Thread[pool-1-thread-1,5,main] 客户端( /127.0.0.1:4644 ) 请求 : Query Date
Thread[pool-1-thread-1,5,main] -- -- -- 添加selectionKey到队列,并唤醒selector
Thread[pool-1-thread-2,5,main] -- -- -- 添加selectionKey到队列,并唤醒selector
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 0
Thread[pool-1-thread-2,5,main] 客户端( /127.0.0.1:4646 ) 请求 : Query Date
Thread[main,5,main] -- -- -- selector被唤醒,注册队列中所有socketChannel为OP_WRITE操作
Thread[pool-1-thread-2,5,main] -- -- -- 添加selectionKey到队列,并唤醒selector
Thread[pool-1-thread-1,5,main] 客户端( /127.0.0.1:4642 ) 请求 : Query Date
Thread[pool-1-thread-1,5,main] -- -- -- 添加selectionKey到队列,并唤醒selector
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[pool-1-thread-2,5,main] 客户端( /127.0.0.1:4647 ) 请求 : Query Date
Thread[pool-1-thread-2,5,main] -- -- -- 添加selectionKey到队列,并唤醒selector
Thread[pool-1-thread-1,5,main] 客户端( /127.0.0.1:4648 ) 请求 : Query Date
Thread[main,5,main] 事件就绪通道个数 : 0
Thread[main,5,main] -- -- -- selector被唤醒,注册队列中所有socketChannel为OP_WRITE操作
Thread[pool-1-thread-1,5,main] -- -- -- 添加selectionKey到队列,并唤醒selector
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 0
Thread[main,5,main] -- -- -- selector被唤醒,注册队列中所有socketChannel为OP_WRITE操作
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 9
Thread[main,5,main] -- -- -- 处理Readable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[pool-1-thread-2,5,main] 客户端( /127.0.0.1:4649 ) 请求 : Query Date
Thread[pool-1-thread-2,5,main] -- -- -- 添加selectionKey到队列,并唤醒selector
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Acceptable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 0
Thread[main,5,main] -- -- -- selector被唤醒,注册队列中所有socketChannel为OP_WRITE操作
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 10
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Acceptable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Readable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 1
Thread[main,5,main] -- -- -- 处理Readable事件
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[pool-1-thread-1,5,main] 客户端( /127.0.0.1:4650 ) 请求 : Query Date
Thread[pool-1-thread-1,5,main] -- -- -- 添加selectionKey到队列,并唤醒selector
Thread[pool-1-thread-2,5,main] 客户端( /127.0.0.1:4651 ) 请求 : Query Date
Thread[main,5,main] 事件就绪通道个数 : 0
Thread[main,5,main] -- -- -- selector被唤醒,注册队列中所有socketChannel为OP_WRITE操作
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[pool-1-thread-2,5,main] -- -- -- 添加selectionKey到队列,并唤醒selector
Thread[main,5,main] 事件就绪通道个数 : 9
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 0
Thread[main,5,main] -- -- -- selector被唤醒,注册队列中所有socketChannel为OP_WRITE操作
Thread[main,5,main] 监听端口@9999,等待客户端连接...
Thread[main,5,main] 事件就绪通道个数 : 10
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] -- -- -- 处理Writable事件
Thread[main,5,main] 监听端口@9999,等待客户端连接...

  Class : Client

Thread[Thread-7,5,main] 服务端响应 : Sat Jun 24 16:00:41 CST 2017
Thread[Thread-0,5,main] 服务端响应 : Sat Jun 24 16:00:41 CST 2017
Thread[Thread-3,5,main] 服务端响应 : Sat Jun 24 16:00:41 CST 2017
Thread[Thread-9,5,main] 服务端响应 : Sat Jun 24 16:00:41 CST 2017
Thread[Thread-1,5,main] 服务端响应 : Sat Jun 24 16:00:41 CST 2017
Thread[Thread-4,5,main] 服务端响应 : Sat Jun 24 16:00:41 CST 2017
Thread[Thread-6,5,main] 服务端响应 : Sat Jun 24 16:00:41 CST 2017
Thread[Thread-5,5,main] 服务端响应 : Sat Jun 24 16:00:41 CST 2017
Thread[Thread-8,5,main] 服务端响应 : Sat Jun 24 16:00:41 CST 2017
Thread[Thread-2,5,main] 服务端响应 : Sat Jun 24 16:00:41 CST 2017

啦啦啦

网络编程 -- RPC实现原理 -- NIO多线程 -- 迭代版本V2的更多相关文章

  1. 网络编程 -- RPC实现原理 -- NIO多线程 -- 迭代版本V1

    网络编程 -- RPC实现原理 -- 目录 啦啦啦 V1——设置标识变量selectionKey.attach(true);只处理一次(会一直循环遍历selectionKeys,占用CPU资源). ( ...

  2. 网络编程 -- RPC实现原理 -- NIO单线程

    网络编程 -- RPC实现原理 -- 目录 啦啦啦 Class : Service package lime.pri.limeNio.optimize.socket; import java.io.B ...

  3. 网络编程 -- RPC实现原理 -- 目录

    -- 啦啦啦 -- 网络编程 -- RPC实现原理 -- NIO单线程 网络编程 -- RPC实现原理 -- NIO多线程 -- 迭代版本V1 网络编程 -- RPC实现原理 -- NIO多线程 -- ...

  4. 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V1 -- 入门应用

    网络编程 -- RPC实现原理 -- 目录 啦啦啦 V1——Netty入门应用 Class : NIOServerBootStrap package lime.pri.limeNio.netty.ne ...

  5. 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V2 -- 对象传输

    网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2——Netty -- 使用序列化和反序列化在网络上传输对象:需要实现 java.io.Serializable 接口 只能传输( ByteBuf ...

  6. 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V3 -- 编码解码

    网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2——Netty -- pipeline.addLast(io.netty.handler.codec.MessageToMessageCodec ...

  7. 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V4 -- 粘包拆包

    网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2——Netty -- new LengthFieldPrepender(2) : 设置数据包 2 字节的特征码 new LengthFieldB ...

  8. 网络编程 -- RPC实现原理 -- RPC -- 迭代版本V3 -- 远程方法调用 整合 Spring

    网络编程 -- RPC实现原理 -- 目录 啦啦啦 V3——RPC -- 远程方法调用 及 null的传输 + Spring 服务提供商: 1. 配置 rpc03_server.xml 注入 服务提供 ...

  9. 网络编程 -- RPC实现原理 -- RPC -- 迭代版本V4 -- 远程方法调用 整合 Spring 自动注册

    网络编程 -- RPC实现原理 -- 目录 啦啦啦 V4——RPC -- 远程方法调用 + Spring 自动注册 服务提供商: 1. 配置 rpc04_server.xml 注入 服务提供商 rpc ...

随机推荐

  1. How to modify analog output range of Arduino Due

    Voltage Translation for Analog to Digital Interface ADC How to modify analog output range of Arduino ...

  2. C#获取类名为Internet_Explorer_Server控件的内容

    为了让大家都能够使用demo,我以IE为测试对象,另外为了突出重点,所以如何获取窗口句柄我就不做演示了(不清楚的童鞋,可以去Google下哈),句柄值我使用spy++获得 大家可以下载demo(附:s ...

  3. c# pictureBox1.Image的获得图片路径的三种方法 winform

    代码如下:c# pictureBox1.Image的获得图片路径的三种方法 winform 1.绝对路径:this.pictureBox2.Image=Image.FromFile("D:\ ...

  4. C# SpinWait 实现

    其实SpinWait的code 非常简单,以前看过很多遍,但是从来都没有整理过,整理也是再次学习吧. 我们先看看SpinWait的一些评论或者注意点吧:如果等待某个条件满足需要的时间很短,而且不希望发 ...

  5. iOS开发-适配器和外观模式

    适配器模式,属于结构型模式,其主要作用是将一个类的接口转换成客户希望的另外一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作.适配器模式有对象适配器和类适配器两种,类适配器模 ...

  6. 【转】《iOS7 by Tutorials》系列:iOS7的设计精髓(下)

    四.聚焦于内容 在iOS7里,强调的不是眼花缭乱的装饰效果,而是最重要的内容本身. 下面我们来探讨这个主题: 1.删除不必要的内容 伟大的设计更多是减法和加法的组合. 虽然很酷的想法是很重要,但还有更 ...

  7. 基于Ubuntu搭建Seafile专属网盘

    系统要求: Ubuntu 16.04.1 LTS 64 位操作系统 安装 Seafile 服务器 安装依赖环境 在 Debian/Ubuntu 系统下,可以使用以下命令安装 MySQL: sudo a ...

  8. Swift 命令行输入输出

    1.类输出 Swift 语言中类输出方法重写 override var description: String { return String(format: "%@, %@", ...

  9. 11G新特性 -- flashback data archive(2)

    创建Flashback Data Archive用户需要授予dba或flashback archive administer系统特权.flashback archive administer系统特权包 ...

  10. Effective Java 第三版——44. 优先使用标准的函数式接口

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...