
疯狂Java讲义:使用NIO实现非阻塞Socket通信(2)[2]
服务器端的Selector仅需要监听两种操作 连接和读数据 所以程序中分别处理了这两种操作 如程序中②和③代码所示 处理连接操作之时 系统只需将接受连接后产生的SocketChannel注册到指定Selector对象即可 处理读数据操作之时 系统先从该Socket中读取数据 再将数据写入Selector上注册的所有Channel
使用NIO来实现服务器时 甚至无须使用ArrayList来保存服务器中所有SocketChannel 因为所有的SocketChannel都需要注册到指定的Selector对象 除此之外 当客户端关闭时会导致服务器对应的Channel也抛出异常 而且本程序只有一条线程 如果该异常得不到处理将会导致整个服务器退出 所以程序捕捉了这种异常 并在处理异常时从Selector删除异常Channel的注册 如程序中斜体字代码所示
本示例程序的客户端程序需要两个线程 一个线程负责读取用户的键盘输入 并将输入的内容写入SocketChannel中 另一个线程则不断地查询Selector对象的select()方法的返回值
程序清单 codes/ / /NoBlock/NClient java
public class NClient
{
//定义检测SocketChannel的Selector对象
private Selector selector = null;
//定义处理编码和解码的字符集
private Charset charset = Charset forName( UTF )
//客户端SocketChannel
private SocketChannel sc = null;
public void init()throws IOException
{
selector = Selector open()
InetSocketAddress isa = new InetSocketAddress( )
//调用open静态方法创建连接到指定主机的SocketChannel
sc = SocketChannel open(isa)
//设置该sc以非阻塞方式工作
sc configureBlocking(false)
//将SocketChannel对象注册到指定Selector
sc register(selector SelectionKey OP_READ)
//启动读取服务器端数据的线程
new ClientThread() start()
//创建键盘输入流
Scanner scan = new Scanner(System in)
while (scan hasNextLine())
{
//读取键盘输入
String line = scan nextLine()
//将键盘输入的内容输出到SocketChannel中
sc write(charset encode(line))
}
}
//定义读取服务器数据的线程
private class ClientThread extends Thread
{
public void run()
{
try
{
while (selector select() > )
{
//遍历每个有可用IO操作Channel对应的SelectionKey
for (SelectionKey sk : selector selectedKeys())
{
//删除正在处理的SelectionKey
selector selectedKeys() remove(sk)
//如果该SelectionKey对应的Channel中有可读的数据
if (sk isReadable())
{
//使用NIO读取Channel中的数据
SocketChannel sc = (SocketChannel)sk channel()
ByteBuffer buff = ByteBuffer allocate( )
String content = ;
while(sc read(buff) > )
{
sc read(buff)
buff flip()
content += charset decode(buff)
}
//打印输出读取的内容
System out println( 聊天信息 + content)
//为下一次读取作准备
sk interestOps(SelectionKey OP_READ)
}
}
}
}
catch (IOException ex)
{
ex printStackTrace()
}
}
}
public static void main(String[] args)
throws IOException
{
new NClient() init()
}
}
相比之下 客户端程序比服务器程序要简单多了 客户端只有一条SocketChannel 将该SocketChannel注册到指定Selector后 程序启动另一条线程来监测该Selector即可
返回目录 疯狂Java讲义
编辑推荐
Java程序性能优化 让你的Java程序更快 更稳定
新手学Java 编程
Java程序设计培训视频教程
lishixinzhi/Article/program/Java/hx/201311/27262