知识大全 使用NIO实现非阻塞Socket通信(1)
Posted 操作
篇首语:枕上从妨一夜睡,灯前读尽十年诗。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 使用NIO实现非阻塞Socket通信(1)相关的知识,希望对你有一定的参考价值。
疯狂Java讲义:使用NIO实现非阻塞Socket通信(1) 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
使用NIO实现非阻塞Socket通信
从JDK 开始 Java提供的NIO API来开发高性能网络服务器 前面介绍的网络通信程序是基于阻塞式API的 即当程序执行输入 输出操作后 在这些操作返回之前会一直阻塞该线程 所以服务器必须为每个客户端都提供一条独立线程进行处理 当服务器需要同时处理大量客户端时 这种做法会导致性能下降 使用NIO API则可以让服务器使用一个或有限几个线程来同时处理连接到服务器上的所有客户端
如果读者忘记了NIO里Channel Buffer Charset等API的概念和用法 读者可以再次阅读本书第 章关于新IO的内容
Java的NIO为非阻塞式的Socket通信提供了如下几个特殊类
Selector:它是SelectableChannel对象的多路复用器 所有希望采用非阻塞方式进行通信的Channel都应该注册到Selector对象 可通过调用此类的静态open()方法来创建Selector实例 该方法将使用系统默认的Selector来返回新的Selector
Selector可以同时监控多个SelectableChannel的IO状况 是非阻塞IO的核心 一个Selector实例有 个SelectionKey的集合
所有SelectionKey集合 代表了注册在该Selector上的Channel 这个集合可以通过keys()方法返回
被选择的SelectionKey集合 代表了所有可通过select()方法监测到 需要进行IO处理的Channel 这个集合可以通过selectedKeys()返回
被取消的SelectionKey集合 代表了所有被取消注册关系的Channel 在下一次执行select()方法时 这些Channel对应的SelectionKey会被彻底删除 程序通常无须直接访问该集合
除此之外 Selector还提供了系列和select()相关的方法 如下所示
int select() 监控所有注册的Channel 当它们中间有需要处理的IO操作时 该方法返回 并将对应的SelectionKey加入被选择的SelectionKey集合中 该方法返回这些Channel的数量
int select(long timeout) 可以设置超时时长的select()操作
int selectNow() 执行一个立即返回的select()操作 相对于无参数的select()方法而言 该方法不会阻塞线程
Selector wakeup() 使一个还未返回的select()方法立刻返回
SelectableChannel:它代表可以支持非阻塞IO操作的Channel对象 可以将其注册到Selector上 这种注册的关系由SelectionKey实例表示
Selector对象提供了一个select()方法 该方法允许应用程序同时监控多个IO Channel
应用程序可调用SelectableChannel 的register()方法将其注册到指定Selector上 当该Selector上某些SelectableChannel上有需要处理的IO操作时 程序可以调用Selector实例的select()方法获取它们的数量 并可以通过selectedKeys()方法返回它们对应的SelectKey集合 通过该集合就可以获取所有需要处理IO操作的SelectableChannel集
SelectableChannel对象支持阻塞和非阻塞两种模式(所有channel默认都是阻塞模式) 必须使用非阻塞式模式才可以利用非阻塞IO操作
SelectableChannel提供了如下两个方法来设置和返回该Channel的模式状态
SelectableChannel configureBlocking(boolean block) 设置是否采用阻塞模式
boolean isBlocking() 返回该Channel是否是阻塞模式
不同的SelectableChannel所支持的操作不一样 例如ServerSocketChannel代表一个ServerSocket 它就只支持OP_ACCEPT操作
SelectableChannel提供如下方法来返回它支持的所有操作
int validOps() :返回一个bit mask 表示这个channel上支持的IO操作
在SelectionKey中 用静态常量定义了 种IO操作 OP_READ( ) OP_WRITE( ) OP_CONNECT( ) OP_ACCEP( ) 这四值任意 个 个 个进行按位或的结果和相加的结果相等 而且它们任意 个 个 个相加的结果总是互不相同 所以系统可以根据validOps()方法的返回值确定该SelectableChannel支持的操作 例如返回 我们知道它支持读( )和写( )
除此之外 SelectableChannel还提供了如下几个方法来获取它的注册状态
boolean isRegistered() 返回该Channel是否已注册在一个或多个Selector上
SelectionKey keyFor(Selector sel) 返回该Channel和sel Selector之间的注册关系 如果不存在注册关系 则返回null
SelectionKey:该对象代表SelectableChannel和Selector之间的注册关系
ServerSocketChannel:支持非阻塞操作 对应于java net ServerSocket这个类 提供了TCP协议IO接口 只支持OP_ACCEPT操作 该类也提供了accept()方法 功能相当于ServerSocket提供的accept()方法
SocketChannel:支持非阻塞操作 对应于java net Socket这个类 提供了TCP协议IO接口 支持OP_CONNECT OP_READ和OP_WRITE操作 这个类还实现了ByteChannel接口 ScatteringByteChannel接口和GatheringByteChannel接口 所以可以直接通过SocketChannel来读写ByteBuffer对象
图 显示了使用NIO实现非阻塞式服务器的示意图
图 NIO的非阻塞式服务器示意
从图 中可以看出 服务器上所有Channel(包括ServerSocketChannel和SocketChannel)都需要向Selector注册 而该Selector则负责监视这些Socket的IO状态 当其中任意一个或多个Channel具有可用的IO操作时 该Selector的select()方法将会返回大于 的整数 该整数值就表示该Selector上有多少个Channel具有可用的IO操作 并提供了selectedKeys()方法来返回这些Channel对应的SelectionKey集合 正是通过Selector 使得服务器端只需要不断地调用Selector实例的select()方法即可知道当前所有Channel是否有需要处理的IO操作
当Selector上注册的所有Channel都没有需要处理的IO操作时 select()方法将被阻塞 调用该方法的线程被阻塞
本示例程序使用NIO实现了多人聊天室的功能 服务器使用循环不断获取Selector的select()方法返回值 当该返回值大于 时就处理该Selector上被选择SelectionKey所对应的Channel
服务器端需要使用ServerSocketChannel来监听客户端的连接请求 Java中该类的设计比较糟糕 它不是ServerSocket的完整抽象 所以不能直接让该Channel监听某个端口 而且不允许使用ServerSoceket的getChannel()方法来获取ServerSocketChannel实例 程序必须先调用它的socket()方法获得关联ServerSocket对象 再用该ServerSocket对象绑定到来指定监听IP和端口 创建一个可用的ServerSocketChannel需采用如下代码片段
//通过open方法来打开一个未绑定的ServerSocketChannel实例
ServerSocketChannel server = ServerSocketChannel open()
InetSocketAddress isa = new InetSocketAddress( )
//将该ServerSocketChannel绑定到指定IP地址
server socket() bind(isa)
如果需要使用非阻塞方式来处理该ServerSocketChannel 还应该设置它的非阻塞模式 并将其注册到指定的Selector 如下代码片段
//设置ServerSocket以非阻塞方式工作
server configureBlocking(false)
//将server注册到指定Selector对象
server register(selector SelectionKey OP_ACCEPT)
返回目录 疯狂Java讲义
编辑推荐
Java程序性能优化 让你的Java程序更快 更稳定
新手学Java 编程
cha138/Article/program/Java/hx/201311/27263相关参考
疯狂Java讲义:使用NIO实现非阻塞Socket通信(2)[2] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一
JavaNIO(异步IO)Socket通信例子 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! /
疯狂Java讲义:使用Socket进行通信[1] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
首先了解下所谓的javanio是个什么东西! 传统的并发型服务器设计是利用阻塞型网络I/O以多线程的模式来实现的然而由 于系统常常在进行网络读写时处于阻塞状态会大大影响系统的性能自Java开始
一个最简单的Socket通信例子 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 所谓socket
疯狂Java讲义:使用Socket进行通信[2] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
利用Delphi编写Socket通信程序 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!笔者在工作中
Java的socket通信的demo 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! Java代码
运用异步输入输出流编写Socket进程通信 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 杨健(
C#和C++结构体Socket通信 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 最近在用C#做