当前位置:文档之家› JAVA NIO基础知识总结二_2012-1-9

JAVA NIO基础知识总结二_2012-1-9

JA V A NIO基础知识总结二(一)、回顾一下总结一:(1)、NIO的几个概念:①、Buffer :内存块,实质就是一个数组。

NIO数据读或写得中转地。

②、Channel:连接设备的通道。

用于向buffer提供数据或者读取数据,异步I/O支持。

③、Selector :channel事件的监听者,他能检测到一个或多个通道,并将事件分发出去④、SelectionKey:channel上发生的事件,包含了事件的状态信息和时间以及对应的channel。

(2)、在前面总结一中,最后的时候给出了一个完整的关于NIO操作网络套接字的例子,在这里先总结一下构建基于NIO的服务端的一般步骤:①、构造一个Selector②、打开一个serverSocketChannel③、设定serverSocketChannel为非阻塞④、绑定socketserverChannel到一个主机地址和端口⑤、注册selector并告知感兴趣的事情(3)、Channel的状态有四种:①、Connectable:当一个Channel完成socket连接操作已完成或者已失败。

②、Acceptable:当一个Channel已准备好接受一个新的socket连接时,channel是Acceptale③、Readable:当一个channel能被读时。

④、Writable:当一个Channel能被写时为可写状态。

(4)、下面是NIO中的关系图,来自于《java编程思想》(二)、基于多线程的NIO总结一的例子,是基于单线程的,单线程的好处是简单,不用去考虑过于复杂的线程问题,但是仔细想一下,如果数据在网络传输的过程中发生了阻塞呢,那岂不是要花费很多的时间?再者如果我们要实现像QQ中的聊天室呢,如何实现呢?。

为了解决这些问题,我们现在试着采用多线程的,但是采用多线程,会产生很多线程,创建、销毁线程都是要花费时间的,所以这里可以运用到线程池来管理。

下面一个例子是:客户端发来信息,服务端然后转发所有的信息给在线的客户端。

import java.io.IOException;import .InetSocketAddress;import java.nio.ByteBuffer;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.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.logging.Level;import java.util.logging.Logger;public class RSocketServer implements Runnable {private final static int POOLSIZE = 100;// 处理线程池的大小private SelectionKey selectionKey; // 选择键private ExecutorService service =Executors.newFixedThreadPool(POOLSIZE);// 固定大小的线程池private boolean isRunning = true;private Selector selector;// 选择器private String writeMsg;// 需要写的信息private ServerSocketChannel ssc;public RSocketServer() {try {selector = Selector.open();ssc = ServerSocketChannel.open();ssc.configureBlocking(false);ssc.socket().bind(new InetSocketAddress(8080));selectionKey = ssc.register(selector,SelectionKey.OP_ACCEPT);System.out.println("服务器启动成功!正在端口为8080上等待...");} catch (Exception e) {e.printStackTrace();}}public void run() {try {while (isRunning) {int num = -1;try {// 监控注册在selector上的SelectableChannelnum = selector.select();} catch (IOException e) {e.printStackTrace();}if (num == 0) {continue;}Iterator<SelectionKey> it =selector.selectedKeys().iterator();while (it.hasNext()) {SelectionKey key = it.next();it.remove();if (!key.isValid())continue;if (key.isAcceptable()) {getConn(key);} else if (key.isReadable()) {System.out.println("可读");readMsg(key);}else if (key.isValid() && key.isWritable()) {if (writeMsg != null) {System.out.println("可写");RWriter(key);}}else break;}}Thread.yield();} catch (Exception e) {e.printStackTrace();}}private void getConn(SelectionKey key) throws IOException { ssc = (ServerSocketChannel) key.channel();SocketChannel sc = ssc.accept();sc.configureBlocking(false);sc.register(selector, SelectionKey.OP_READ);}private void readMsg(SelectionKey key) throws IOException {StringBuffer sb = new StringBuffer();SocketChannel sc = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);buffer.clear();int len = 0;while ((len = sc.read(buffer)) > 0) {buffer.flip();sb.append(new String(buffer.array(), 0, len));}if (sb.length() > 0)System.out.println("从客户端发来的数据:" + sb.toString());if ("exit".equals(sb.toString().trim())||sb.length()==0) { sc.write(ByteBuffer.wrap("bye".getBytes()));System.out.println("服务端已经关闭");key.cancel();sc.close();sc.socket().close();} else {String msg = sc.socket().getRemoteSocketAddress() + ":"+ sb.toString();Iterator<SelectionKey> it =key.selector().keys().iterator();// 把数据分发到每一个已经连接的客户端while (it.hasNext()) {SelectionKey skey = it.next();if (skey != key && skey != selectionKey) {RWriter myWriter = new RWriter(skey, msg);service.execute(myWriter);}}}}public static void main(String[] args) {RSocketServer server = new RSocketServer();new Thread(server).start();}class RWriter implements Runnable {SelectionKey key;String msg;public RWriter(SelectionKey key, String msg) {this.key = key;this.msg = msg;}public void run() {try {SocketChannel client = (SocketChannel) key.channel();client.write(ByteBuffer.wrap(msg.getBytes()));Thread.yield();} catch (IOException ex) {Logger.getLogger(RWriter.class.getName()).log(Level.SEVERE,null, ex);}}}private void RWriter(SelectionKey key) throws IOException { SocketChannel sc = (SocketChannel) key.channel();String str = (String) key.attachment();sc.write(ByteBuffer.wrap(str.getBytes()));key.interestOps(SelectionKey.OP_READ);}}(三)、Java NIO的Reactor模式看了上面的例子,有没有发觉一些问题呢?会不会觉得例子有点“乱七八糟”的感觉,接收数据、业务逻辑、发送数据、数据的包装等等,这些都需要我们去处理。

相关主题