2、NIO详解之网络编程
2018-04-02 18:10
381 查看
前言
篇将重点介绍基于网络编程NIO(异步IO)。Selector
在我的JavaNIO详解(一)中已经详细介绍了Java NIO三个核心对象中的Buffer和Channel,现在我们就重点介绍一下第三个核心对象Selector。Selector是一个对象,它可以注册到很多个Channel上,监听各个Channel上发生的事件,并且能够根据事件情况决定Channel读写。这样,通过一个线程管理多个Channel,就可以处理大量网络连接了。
有了Selector,我们就可以利用一个线程来处理所有的channels。线程之间的切换对操作系统来说代价是很高的,并且每个线程也会占用一定的系统资源。所以,对系统来说使用的线程越少越好。
但是,需要记住,现代的操作系统和CPU在多任务方面表现的越来越好,所以多线程的开销随着时间的推移,变得越来越小了。实际上,如果一个CPU有多个内核,不使用多任务可能是在浪费CPU能力。只要知道使用Selector能够处理多个通道就足够了。
Selector
1、创建一个Selector
异步 I/O 中的核心对象名为 Selector。Selector 就是您注册对各种 I/O 事件兴趣的地方,而且当那些事件发生时,就是这个对象告诉您所发生的事件。Selector selector = Selector.open();
2、注册Channel到Selector
为了能让Channel和Selector配合使用,我们需要把Channel注册到Selector上。通过调用 channel.register()方法来实现注册:channel.configureBlocking(false); SelectionKey key =channel.register(selector,SelectionKey.OP_READ);
注意,注册的Channel 必须设置成异步模式 才可以,,否则异步IO就无法工作,这就意味着我们不能把一个FileChannel注册到Selector,因为
FileChannel没有异步模式,但是网络编程中的
SocketChannel是可以的。
需要注意register()方法的第二个参数,它是一个“interest set”,意思是注册的
Selector对Channel中的哪些时间感兴趣,事件类型有四种:
. Connect 某个Channel成功连接到另一个服务器称为 Connect Ready
. Accept 一个ServerSocketChannel准备好接收新连接称为 Accept Ready
. Read 一个有数据可读的通道可以说是 Read Ready
. Write 等待写数据的通道可以说是Write Ready。
SelectionKey
1、 请注意对register()的调用的返回值是一个SelectionKey。 SelectionKey 代表这个通道在此 Selector 上的这个注册。当某个 Selector 通知您某个传入事件时,它是通过提供对应于该事件的 SelectionKey 来进行的。SelectionKey 还可以用于取消通道的注册。SelectionKey中包含如下属性:1. SelectionKey.OP_CONNECT 2. SelectionKey.OP_ACCEPT 3. SelectionKey.OP_READ 4. SelectionKey.OP_WRITE
2、、Channel 和Selector
我们可以通过SelectionKey获得Selector和注册的Channel:
Channel channel = selectionKey.channel(); Selector selector = selectionKey.selector();
3、通过Selector选择通道
一旦调用了select()方法,它就会返回一个数值,表示一个或多个通道已经就绪,然后你就可以通过调用selector.selectedKeys()
int num = selector.select();
4、selectedKeys()
一旦调用了select()方法,它就会返回一个数值,表示一个或多个通道已经就绪,然后你就可以通过调用selector.selectedKeys()方法返回的SelectionKey集合来获得就绪的Channel。请看演示方法:
Set<SelectionKey> selectedKeys = selector.selectedKeys();
当你通过Selector注册一个Channel时,channel.register()方法会返回一个SelectionKey对象,这个对象就代表了你注册的Channel。这些对象可以通过selectedKeys()方法获得。你可以通过迭代这些selected key来获得就绪的Channel,下面是演示代码:
Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while(keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if(key.isAcceptable()) { // a connection was accepted by a ServerSocketChannel. } else if (key.isConnectable()) { // a connection was established with a remote server. } else if (key.isReadable()) { // a channel is ready for reading } else if (key.isWritable()) { // a channel is ready for writing } keyIterator.remove(); }
5、举例说明
package com.hlj.nio.Study; import sun.applet.Main; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.nio.ByteBuffer; import java.nio.CharBuffer; 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; /** * @Description * @Author HealerJean * @Date 2018/3/28 下午12:20. */ public class NetNio { public static void main(String[] args) throws IOException { listen(); } static int port = 1111; /* * 注册事件 * */ protected static Selector getSelector() throws IOException { // 创建Selector对象 Selector selector = Selector.open(); // 创建可选择通道,并配置为非阻塞模式 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); // 绑定通道到指定端口 ServerSocket socket = serverSocketChannel.socket(); InetSocketAddress address = new InetSocketAddress(port); socket.bind(address); // 向Selector中注册感兴趣的事件, // 即指定我们想要监听accept事件,也就是新的连接发 生时所产生的事件, // 对于ServerSocketChannel通道来说,我们唯一可以指定的参数就是OP_ACCEPT。 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); return selector; } /* * 开始监 100ee 听 * */ public static void listen() throws IOException { Selector selector = getSelector(); System.out.println("listen on " + port); try { while(true) { //int select(long timeout):select()一样,除了最长会阻塞timeout毫秒(参数) //int selectNow(): 不会阻塞,不管什么通道就绪都立刻返回,此方法执行非阻塞的选择操作。 // 如果自从前一次选择操作后,没有通道变成可选择的,则此方法直接返回零。 // int select() 该调用会阻塞,阻塞到至少有一个通道在你注册的事件上就绪,方法将返回所发生的事件的数量。 //select()方法返回的int值表示有多少通道已经就绪。亦即,自上次调用select()方法后有多少通道变成就绪状态。 // 如果调用select()方法,因为有一个通道变成就绪状态,返回了1, // 若再次调用select()方法,如果另一个通道就绪了,它会再次返回1。 // 如果对第一个就绪的channel没有做任何操作,现在就有两个就绪的通道, // 但在每次select()方法调用之间,只有一个通道处于就绪状态。 int num = selector.select(); Set<SelectionKey> keys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = keys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = (SelectionKey) keyIterator.next(); //Selector对象并不会从自己的selected key集合中自动移除SelectionKey实例。 // 我们需要在处理完一个Channel的时候自己去移除。当下一次Channel就绪的时候, // Selector会再次把它添加到selected key集合中。 keyIterator.remove(); process(key); } } } catch (IOException e) { e.printStackTrace(); } } /* * 根据不同的事件做处理 * */ protected static void process(SelectionKey key) throws IOException{ Selector selector = getSelector(); // 接收请求,Channel中什么事件或操作已经就绪 if (key.isAcceptable()) { ServerSocketChannel server = (ServerSocketChannel) key.channel(); SocketChannel channel = server.accept(); channel.configureBlocking(false); channel.register(selector, SelectionKey.OP_READ); } } }
因为外面还有一个while 死循环
1、请注意循环中最后的keyIterator.remove()方法。Selector对象并不会从自己的selected key集合中自动移除SelectionKey实例。我们需要在处理完一个Channel的时候自己去移除。当下一次Channel就绪的时候,Selector会再次把它添加到selected key集合中。
2、SelectionKey.channel()方法返回的Channel需要转换成你具体要处理的类型,比如是ServerSocketChannel或者SocketChannel等等。
太多了,请观察博客https://blog.csdn.net/suifeng3051/article/details/48441629
如果满意,请打赏博主任意金额,感兴趣的请下方留言吧。可与博主自由讨论哦
支付包 | 微信 | 微信公众号 |
---|---|---|
相关文章推荐
- 详解Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)
- java 高性能网络编程 NIO
- 2015.08.07网络编程read()函数详解
- android 网络编程 HttpGet类和HttpPost类使用详解
- Java网络编程——使用NIO实现非阻塞Socket通信
- 关于孙鑫老师vc++详解第十四章tcp网络编程的乱码“烫烫”的经验
- Android开发使用URLConnection进行网络编程详解
- 在JAVA中使用NIO进行网络编程
- 网络编程基础:对HTTP协议的头信息详解
- Linux网络编程15——I/O复用之poll详解
- iOS网络开发编程之NSURLConnection详解
- android 网络编程 HttpGet类和HttpPost类使用详解
- SE高阶(16):Java网络编程详解
- 高并发网络编程之epoll详解
- TCP-IP学习笔记三:NIO的网络编程-单线程实例
- Java网络Socket编程详解
- 基于NIO的Netty网络框架(详解)
- C++中Socket网络编程实例详解
- 网络编程 详解
- java 网络编程之ServerSocket详解