java nio
2016-08-04 16:53
344 查看
package test; import java.io.IOException; import java.net.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.nio.charset.Charset; import java.util.Iterator; import java.util.Set; public class EchoServer { public static final int SERVER_PORT = 8080; public static SelectorLoop connectionBell; public static SelectorLoop readBell; public boolean isReadBellRunning=false; public static void main(String[] args) throws IOException { new EchoServer().startServer(); } // 启动服务器 public void startServer() throws IOException { // 准备好一个闹钟.当有链接进来的时候响. connectionBell = new SelectorLoop(); // 准备好一个闹装,当有read事件进来的时候响. readBell = new SelectorLoop(); ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.socket().bind(new InetSocketAddress(SERVER_PORT)); ssc.configureBlocking(false); // 给闹钟规定好要监听报告的事件,这个闹钟只监听新连接事件. ssc.register(connectionBell.getSelector(), SelectionKey.OP_ACCEPT); new Thread(connectionBell).start(); } // Selector轮询线程类 public class SelectorLoop implements Runnable { private Selector selector; private ByteBuffer temp = ByteBuffer.allocate(1024); public SelectorLoop() throws IOException { this.selector = Selector.open(); } public Selector getSelector() { return this.selector; } @Override public void run() { while(true) { try { // 阻塞,只有当至少一个注册的事件发生的时候才会继续. this.selector.select(); Set<SelectionKey> selectKeys = this.selector.selectedKeys(); Iterator<SelectionKey> it = selectKeys.iterator(); while (it.hasNext()) { SelectionKey key = it.next(); it.remove(); // 处理事件. 可以用多线程来处理. this.dispatch(key); } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } public void dispatch(SelectionKey key) throws IOException, InterruptedException { if (key.isAcceptable()) { // 这是一个connection accept事件, 并且这个事件是注册在serversocketchannel上的. ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); // 接受一个连接. SocketChannel sc = ssc.accept(); // 对新的连接的channel注册read事件. 使用readBell闹钟. sc.configureBlocking(false); sc.register(readBell.getSelector(), SelectionKey.OP_READ); // 如果读取线程还没有启动,那就启动一个读取线程. synchronized(EchoServer.this) { if (!EchoServer.this.isReadBellRunning) { EchoServer.this.isReadBellRunning = true; new Thread(readBell).start(); } } } else if (key.isReadable()) { // 这是一个read事件,并且这个事件是注册在socketchannel上的. SocketChannel sc = (SocketChannel) key.channel(); // 写数据到buffer int count = sc.read(temp); if (count < 0) { // 客户端已经断开连接. key.cancel(); sc.close(); return; } // 切换buffer到读状态,内部指针归位. temp.flip(); String msg = Charset.forName("UTF-8").decode(temp).toString(); System.out.println("Server received ["+msg+"] from client address:" + sc.getRemoteAddress()); Thread.sleep(1000); // echo back. sc.write(ByteBuffer.wrap(msg.getBytes(Charset.forName("UTF-8")))); // 清空buffer temp.clear(); } } } }
相关文章推荐
- 浅克隆与深克隆的区别-java
- Java向MySQL数据库插入时间类型Date数据时需要注意的问题
- Eclipse CDT
- java获取当前日期时间代码
- eclipse使用
- Java键盘字符乱码判断代码
- 自定义注解之源码注解(RetentionPolicy.SOURCE)
- Java 并发编程实战 摘要
- 关于eclipse安装PyDev后preference下始终没有Pydev选项的解决方案
- Java基础知识[0]
- Java 字符串格式化,正则解析数据
- Java 原子操作的原理和问题
- java对象序列化的问题
- java如何随机生成6位数的验证码
- 解决Spring Security导致的前后台传值乱码问题
- Java 异常处理
- 01JavaIO详解_File类
- Spring缓存注解@Cache使用
- java中异常
- 从零接触java第一周