`

NIO 之Selector.open() 机制解析

阅读更多
最近在学习使用mina这个基于NIO的框架,写了个客户端程序用来测试服务器,大致代码如下:
for(int i=0;i<1000;i++){
   IoConnector connector=new NioSocketConnector();
   connector.setConnectTimeoutMillis(30000);
   connector.getFilterChain().addLast("codec", new  ProtocolCodecFilter(new SmsCodecFactory(Charset.forName("utf-8"))));

    connector.setHandler(new SmsClientHandler());
    connector.connect(new InetSocketAddress("localhost", 9123));
}

循环还没跑结束就抛出了如下的异常:
Exception in thread "main" org.apache.mina.core.RuntimeIoException: Failed to create a new instance of org.apache.mina.transport.socket.nio.NioProcessor:null
at org.apache.mina.core.service.SimpleIoProcessorPool.<init>(SimpleIoProcessorPool.java:200)
at org.apache.mina.core.service.SimpleIoProcessorPool.<init>(SimpleIoProcessorPool.java:114)
at org.apache.mina.core.polling.AbstractPollingIoConnector.<init>(AbstractPollingIoConnector.java:95)
at org.apache.mina.transport.socket.nio.NioSocketConnector.<init>(NioSocketConnector.java:55)
at com.lijun.sms.client.SmsFakeClient.main(SmsFakeClient.java:26)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedConstructorAccessor1.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.apache.mina.core.service.SimpleIoProcessorPool.<init>(SimpleIoProcessorPool.java:182)
... 4 more
Caused by: org.apache.mina.core.RuntimeIoException: Failed to open a selector.
at org.apache.mina.transport.socket.nio.NioProcessor.<init>(NioProcessor.java:61)
... 8 more
Caused by: java.io.IOException: Unable to establish loopback connection
at sun.nio.ch.PipeImpl$Initializer.run(PipeImpl.java:106)
at java.security.AccessController.doPrivileged(Native Method)
at sun.nio.ch.PipeImpl.<init>(PipeImpl.java:122)
at sun.nio.ch.SelectorProviderImpl.openPipe(SelectorProviderImpl.java:27)
at java.nio.channels.Pipe.open(Pipe.java:133)
at sun.nio.ch.WindowsSelectorImpl.<init>(WindowsSelectorImpl.java:104)
at sun.nio.ch.WindowsSelectorProvider.openSelector(WindowsSelectorProvider.java:26)
at java.nio.channels.Selector.open(Selector.java:209)
at org.apache.mina.transport.socket.nio.NioProcessor.<init>(NioProcessor.java:59)
... 8 more
Caused by: java.net.SocketException: No buffer space available (maximum connections reached?): connect
at sun.nio.ch.Net.connect(Native Method)
at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:500)
at java.nio.channels.SocketChannel.open(SocketChannel.java:146)
at sun.nio.ch.PipeImpl$Initializer.run(PipeImpl.java:78)
... 16 more

看了下异常栈,看来是NIO 的Selector.open()方法调用的时候出现了问题,接下来就是google看别人是不是也遇到过这样的问题了,果然已经有很多人遇到过,具体的解释就如下文了:
原因是每个Selector都会打开一个loopback接连(就是自己连接到自己).在win上是TCP,在linux是pipe.loopback资源有限,打开的Selector一多自然就报错了.

如果要追述具体原因,这和Sun实现Selector的wakeup方法有关.JDK API里面这么写着的:

public abstract Selector wakeup()使尚未返回的第一个选择操作立即返回。
如果另一个线程目前正阻塞在 select() 或 select(long) 方法的调用中,则该调用将立即返回。如果当前未进行选择操作,那么在没有同时调用 selectNow() 方法的情况下,对上述方法的下一次调用将立即返回。在任一情况下,该调用返回的值可能是非零的。如果未同时再次调用此方法,则照常阻塞 select() 或 select(long) 方法的后续调用。

在两个连续的选择操作之间多次调用此方法与只调用一次的效果相同。


返回:
此选择器


当我们调用select()方法的时候是阻塞的.被阻塞的线程有三个方法被唤醒:

1)  有数据可读/写,或出现异常。

2)  阻塞时间到,即time out。

3)  收到一个non-block的信号。可由kill或pthread_kill发出。



所以,Selector.wakeup()要唤醒阻塞的select,那么也只能通过这三种方法,其中:

1)第二种方法可以排除,因为select一旦阻塞,应无法修改其time out时间。

2)而第三种看来只能在Linux上实现,Windows上没有这种信号通知的机制。

  所以,看来只有第一种方法了。再回想到为什么每个Selector.open(),在Windows会建立一对自己和自己的loopback的TCP连接;在Linux上会开一对pipe(pipe在Linux下一般都是成对打开),估计我们能够猜得出来——那就是如果想要唤醒select,只需要朝着自己的这个loopback连接发点数据过去,于是,就可以唤醒阻塞在select上的线程了。

具体到我的case, 每次我通过IoConnector.connect()建立和server的连接时,都会调用Selector.open()方法,这样一旦次数达到一定的数目,相应的资源就被消耗完了。
分享到:
评论

相关推荐

    Java-NIO类库Selector机制解析.docx

    "Java NIO Selector 机制解析" Java NIO(New I/O)类库是Java 1.4版本以后引入的新一代I/O机制,相比传统的I/O机制,NIO提供了高效、异步、多路复用的I/O操作模式。Selector机制是NIO类库中的一种核心机制,用于...

    java NIO详细教程

    ### Java NIO 详细教程知识点解析 #### 一、Java NIO 概述 Java NIO(New IO)是Java平台提供的一种新的IO操作模式,它首次出现在Java 1.4版本中,并在后续版本中不断完善。Java NIO 的设计目的是为了克服传统Java ...

    NIO流程.txt

    Selector selector = Selector.open(); ``` 这一步创建了一个选择器实例,用于后续监听多个Channel的状态变化。 2. **打开服务器通道**: ```java ServerSocketChannel server = ServerSocketChannel.open(); ...

    nio socket编程java代码示例,客户端发送消息,服务端接收

    本示例将详细解析如何使用Java的非阻塞I/O(NIO)实现Socket通信,包括客户端发送消息和服务器端接收消息的过程。 首先,理解NIO(Non-blocking Input/Output)的概念至关重要。NIO与传统的IO模型不同,它提供了对...

    NIO 服务器客户端例子

    这个简单的例子展示了如何使用Java NIO实现服务器和客户端的基本通信流程,但实际应用中可能还需要处理异常、数据解析、心跳检测等复杂逻辑。理解NIO的核心概念和API,对于构建高效、可扩展的网络应用至关重要。

    java selector类的用法举例

    `Selector`是Java NIO的核心组件之一,它能够同时监控多个注册过的`Channel`的状态,从而允许单个线程处理多个输入流,提高了程序的性能。当`Selector`检测到一个或多个`Channel`已经准备好进行I/O操作时,它会提供...

    android nio程序

    总结,`android nio`提供了高效的数据传输机制和并发处理能力,`NioServer`和`NioClient`是理解和实践这一技术的典型示例。通过深入理解这些概念和示例,开发者可以构建出更稳定、更高效的Android网络应用。

    Java_NIO原理解析

    1. **创建选择器**:通过调用`Selector.open()`方法创建一个选择器实例。 2. **配置通道**:打开通道(如ServerSocketChannel),并将其设置为非阻塞模式,`ssc.configureBlocking(false)`。 3. **注册通道**:将...

    android开发进阶之NIO非阻塞包

    6. **Selector机制**:`Selector`是NIO中用于多路复用的关键组件,它可以监听多个`Channel`的事件(如可读、可写等),当某个`Channel`准备好时,`Selector`会通知应用程序进行相应的处理。这使得单个线程能够有效地...

    Java NIO 细节也精彩

    ### Java NIO 的精彩细节解析 #### 一、Selector的Wakeup原理 ##### 1.1 背景介绍 在Java NIO (Non-blocking I/O)中,`Selector` 是核心组件之一,用于监控多个`Channel`上的I/O事件(如可读、可写等)。`...

    多线程NIO客户端实例

    - 使用`SocketChannel.open()`方法创建了一个非阻塞模式的SocketChannel,并通过`Selector.open()`创建了一个选择器`sl`,用于监听SocketChannel的事件。 - 调用`connect(ad)`方法尝试连接至服务器,其中`ad`是...

    Java Socket学习---nio实现阻塞多线程通信

    在NIO中,我们通常使用`Selector`来监控多个`Channel`,而不是像传统的BIO(阻塞I/O)那样为每个连接创建一个新的线程。这样可以显著减少线程数量,提高服务器的并发能力。 1. `Selector`注册:服务器会创建一个`...

    JAVA IO-NIO 详解

    - **创建**: 通过Selector.open()方法。 **2. 注册Channel** - **注册**: 通过Channel的register方法将Channel注册到Selector。 - **事件类型**: 指定感兴趣的事件类型,如SelectionKey.OP_READ。 **3. 选择** -...

    mldn nio ppt 源码

    NIO的核心在于Channel和Buffer,以及Selector的选择器机制,它提供了更高效、更灵活的I/O操作方式。本篇将通过分析mldn nio ppt源码,深入探讨NIO的关键概念和应用。 首先,我们需要了解传统的Java I/O模型(BIO)...

    c学习

    总结来说,这个压缩包文件可能包含了一篇或两篇深入解析Java NIO选择器机制的文章,特别是结合Linux poll机制的使用,对于学习和掌握Java NIO编程具有很高的价值。对于想要提升服务器性能、处理大量并发连接的开发者...

    socket文件传输部分代码(java)

    Selector selector = Selector.open(); SelectionKey key = r_channel.register(selector, SelectionKey.OP_READ); ``` 在非阻塞模式下,将`SocketChannel`注册到选择器上,并指定监听读事件。 3. **循环读取...

    MyTomcat.rar

    通过`Selector.open()`方法创建选择器,并使用`register()`方法将ServerSocketChannel注册到选择器上,指定感兴趣的事件类型。 3. **接收连接**:当有新的客户端连接请求时,服务器会接收到一个Accept事件。此时,...

    scalable-io-in-java-中文1

    例如,`Selector.open()`创建Selector,`ServerSocketChannel.bind()`建立监听,`ServerSocketChannel.register()`将通道注册到Selector上,`Selector.select()`阻塞直到有事件发生,然后通过`selectedKeys()`获取并...

    Netty面试专题

    - **概念**:NIO的核心组件之一,用于存储数据。 - **常用方法**: - `flip()`:反转缓冲区状态,准备读取数据。 - `clear()`:清除缓冲区,准备好写入新数据。 - `rewind()`:重置位置指针,回到缓冲区起始...

Global site tag (gtag.js) - Google Analytics