最近给内部做了一个NIO的分享,是基于JKD1.6的JDK的,由于我不喜欢写PPT,所以就只写了一个DEMO,现在把代码拿出来分享一下,关于NIO的使用方法,以及如何扩展都在代码的注释里面写着的,希望对需要的同学有帮助。
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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.Date;
import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author coffee
* mail:coffee_hc@163.com
*/
public class NIoTest {
private static Logger logger = LoggerFactory.getLogger(NIoTest.class);
private Selector acceptSelector;
private Selector rwSelector;
private BlockingQueue<SocketChannel> waitRegeditChannel = new LinkedBlockingQueue<SocketChannel>();
public static void main(String[] args) {
NIoTest ns = new NIoTest();
ns.start();
}
public void start() {
InetSocketAddress localAddress = new InetSocketAddress("127.0.0.1", 8888);
ServerSocketChannel serverSocketChannel;
try {
acceptSelector = Selector.open();
rwSelector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
// 非堵塞
serverSocketChannel.configureBlocking(false);
ServerSocket socket = serverSocketChannel.socket();
// 端口不复用
socket.setReuseAddress(false);
socket.setSoTimeout(60000);
socket.setReceiveBufferSize(1024);
socket.bind(localAddress);
serverSocketChannel.register(acceptSelector, SelectionKey.OP_ACCEPT);
Executor e = Executors.newFixedThreadPool(2);// 这里可以不用线程池
e.execute(new Accept());
e.execute(new RWThread());
} catch (IOException e) {
e.printStackTrace();
}
}
public class Accept implements Runnable {
@Override
public void run() {
while (true) {
try {
int count = acceptSelector.select(500);
// logger.debug("accept");
if (count > 0) {
Iterator<SelectionKey> keys = acceptSelector.selectedKeys().iterator();
while (keys.hasNext()) {
SelectionKey key = keys.next();
// 一定要删除
keys.remove();
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
// 接受了才能获取连接的通道
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
// 取消以下注释代码,会导致通道在选择器中注册的时候与选择器在选择的时候争抢互斥锁,很难被注册进去。
// logger.debug("开始注册连接");
// socketChannel.register(rwSelector,
// SelectionKey.OP_READ);
// logger.debug("结束注册连接");
waitRegeditChannel.put(socketChannel);
// 当然,可以建立一个选择器池,并发处理接受的连接,具体如何实现自己扩展
rwSelector.wakeup();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private class RWThread implements Runnable {
/*
* (non-Javadoc)
*
* @see java.lang.Thread#run()
*/
@Override
public void run() {
while (true) {
try {
while (!waitRegeditChannel.isEmpty()) {
SocketChannel socketChannel = waitRegeditChannel.poll();
socketChannel.register(rwSelector, SelectionKey.OP_READ);// 此处需要改造
logger.debug("注册了一个连接:" + socketChannel.socket());
}
int count = rwSelector.select(1000);
// logger.debug("rw");
if (count > 0) {
Iterator<SelectionKey> keys = rwSelector.selectedKeys().iterator();
while (keys.hasNext()) {
SelectionKey key = keys.next();
keys.remove();
// 此处可以扩展为将数据放到线程池中处理,这样可以提高数据的吞吐量,但是要注意内存的处理
processKey(key);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void processKey(SelectionKey key) {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer bb = ByteBuffer.allocate(1024);
int count;
try {
// 此处加断点以后可以明显看到,OS底层的TCP会缓存数据,read的时候将会一次性读出来。
count = socketChannel.read(bb);
if (count < 0) {
// 已经读到流的结尾,或连接异常,需要关闭连接
socketChannel.close();
// 注意key.cancel()是在下次select()的时候才会被清理
key.cancel();
return;
}
} catch (IOException e) {
e.printStackTrace();
}
// buffer的使用一定要好好看看API,buffer的熟练使用对NIO编程很重要
bb.flip();
int limit = bb.limit();
byte[] tmpbytes = new byte[limit];
bb.get(tmpbytes);
logger.debug("接受信息为:" + new String(tmpbytes));
if (!isCache(key, tmpbytes)) {
byte[] bytes = (byte[]) key.attachment();
String requestStr = new String(bytes);
logger.debug("请求字符串:" + requestStr);
bb.clear();
if (requestStr.equals("gettime")) {
bb.put(new Date().toString().getBytes());
key.attach(new byte[0]);
} else if (requestStr.endsWith("clear")) {
key.attach(new byte[0]);
try {
bb.put("缓存已清理".getBytes("GB2312"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else {
try {
bb.put("不能识别的请求".getBytes("GB2312"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
bb.flip();
try {
socketChannel.write(bb);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private boolean isCache(SelectionKey key, byte[] tmpbytes) {
Object obj = key.attachment();
byte[] bytes;
if (obj != null) {
bytes = (byte[]) obj;
} else {
bytes = new byte[0];
}
int sumLength = bytes.length + tmpbytes.length;
ByteBuffer bb = ByteBuffer.allocate(sumLength);
bb.put(bytes);
bb.put(tmpbytes);
bb.flip();
tmpbytes = bb.array();
if (tmpbytes[sumLength - 1] == 10) {
tmpbytes = new byte[sumLength - 2];
bb.get(tmpbytes);
key.attach(tmpbytes);
return false;
} else {
key.attach(tmpbytes);
return true;
}
}
}
}
分享到:
相关推荐
一个NIO服务端,客户端的例子
一个java NIO的例子 有很详细的每一步的描述,很好去理解
Java NIO系列教程(一) Java NIO 概述
举个例子吧 你服务器做一个聊天室 按照以前的阻塞式IO 你必须为每个连接创建一个线程 因为当你调用如 in read buf 时 线程会阻塞在这里 而采用nio 只要注册了事件 它内部采用反应模式 当有IO事件发生时 再调度它 而...
Java NIO系列教程(一) Java NIO 概述 Java NIO系列教程(二) Channel Java NIO系列教程(三) Buffer Java NIO系列教程(四) Scatter/Gather Java NIO系列教程(五) 通道之间的数据传输 Java NIO系列教程(六)...
在标准 IO 中,数据是以流的形式读取和写入的,而 NIO 则将数据读取到一个缓冲区,然后再进行处理。 2. 同步和异步 标准 IO 流是线程堵塞和同步的,当一个线程调用了 read() 或 write() 方法时,该线程将被堵塞,...
Java NIO 深入探讨了 1.4 版的 I/O 新特性,并告诉您如何使用这些特性来极大...NIO API 是对 1.3 版 I/O 特性的补充而非取代,因此,何时使用新的 API,何时老的 1.3 版 I/O API 更适合特定应用,也是您将学习的内容。
NIO入门.chm NIO入门.chm NIO入门.chm
NULL 博文链接:https://hujiqiang.iteye.com/blog/642805
一个非常简单的java nio通信的例子,服务器接收到来自客户端的字符串后,计算该字符串的哈希值,然后返回给客户端
java NIO.zip
java nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socket
自JDK-1.4开始的新I/O...效率的提高主要来源于一个新的内存共享技术。传统上,Java内存来自JVM的堆,Native code(JNI)不能很好的与Java code共享这些Java内存,因为Native code对这些Java内存的访问和使用受到很多的限制
Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式。 Java NIO: Channels and Buffers(通道和缓冲区) 标准的IO基于字节流和字符流进行操作的,...
Java的IO操作集中在java.io这个包中,是基于流的同步(blocking)API。对于大多数应用来说,这样...从JDK 1.4起,NIO API作为一个基于缓冲区,并能提供异步(non-blocking)IO操作的API被引入。本文对其进行深入的介绍。
在您学习了本教程以后,这些代码将为您的 NIO 编程努力提供一个起点。 本教程是为希望学习更多关于 JDK 1.4 NIO 库的知识的所有程序员而写的。为了最大程度地从这里的讨论中获益,您应该理解基本的 Java 编程概念,...
java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java...
Java NIO英文高清原版
NIO和AIO介绍NIO和AIO介绍NIO和AIO介绍NIO和AIO介绍NIO和AIO介绍NIO和AIO介绍NIO和AIO介绍NIO和AIO介绍NIO和AIO介绍NIO和AIO介绍NIO和AIO介绍NIO和AIO介绍NIO和AIO介绍NIO和AIO介绍NIO和AIO介绍
Java IO NIO and NIO 2 英文无水印pdf pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn...