NIO编程
来源:互联网 发布:淘宝自刷平台 编辑:程序博客网 时间:2024/06/07 05:47
这里首先声明:我导入的jar包是5.0的jar包。
在写这个demo之前最好先学习一下NIO 的基础方法,至少知道哪个方法是干什么用的。
这篇博文的代码实现了一个简单的时间服务器:客户端发送请求,服务端判断接收到的请求返回不同的信息。
NIO服务端代码:
public class TimeServer {public static void main(String[] args) {int port = 9090;if(args!=null&&args.length>0){try{port = Integer.valueOf(args[0]);}catch(NumberFormatException e){//采用默认值}}/** * 创建一个多路复用类,它是一个独立的线程,负责轮询多路复用器Selector * 可以处理多个客户端的并发接入 */MultiplexerTimeServer timeServer = new MultiplexerTimeServer(port);new Thread(timeServer,"NIO-MultiplexerTimeServer-001").start();}
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.util.Iterator;import java.util.Set;public class MultiplexerTimeServer implements Runnable {private Selector selector;private ServerSocketChannel servChannel;private volatile boolean stop;/** * 初始化多路复用器、绑定监听窗口 * * @param port */public MultiplexerTimeServer(int port) {try {//多路复用器,可以同时轮询多个Channelselector = Selector.open();//打开ServerSocketChannel,用于监听客户端的连接servChannel = ServerSocketChannel.open();//绑定监听的端口,设置连接为非阻塞模式servChannel.configureBlocking(false);servChannel.socket().bind(new InetSocketAddress(port), 1024);//将ServerSocketChannel注册到多路复用器上,监听ACCEPT事件servChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("The time server is start in port :" + port);} catch (IOException e) {e.printStackTrace();System.exit(1);}}public void stop() {this.stop = true;}@Overridepublic void run() {while (!stop) {try {//多路复用器在线程run方法的无限循环体内轮询准备就绪的Keyselector.select(1000);Set<SelectionKey> selectionKey = selector.selectedKeys();Iterator<SelectionKey> it = selectionKey.iterator();SelectionKey key = null;while (it.hasNext()) {key = it.next();it.remove();try {handleInput(key);} catch (Exception e) {key.channel();if (key.channel() != null)key.channel().close();}}} catch (Throwable t) {t.printStackTrace();}}/** * 多路复用器关闭后,所有注册在上面的Channel和Pipe等资源都会被自动去注册 并关闭,所以不需要重复释放资源 */if (selector != null) {try {selector.close();} catch (IOException e) {e.printStackTrace();}}}private void handleInput(SelectionKey key) throws IOException {if(key.isValid()){//处理新接入的请求消息if(key.isAcceptable()){//接收新的连接ServerSocketChannel ssc = (ServerSocketChannel) key.channel();SocketChannel sc = ssc.accept();sc.configureBlocking(false);//添加新的连接到多路复用器sc.register(selector, SelectionKey.OP_READ);}if(key.isReadable()){//读取数据SocketChannel sc = (SocketChannel) key.channel();ByteBuffer readBuffer = ByteBuffer.allocate(1024);int readBytes = sc.read(readBuffer);if(readBytes>0){readBuffer.flip();byte[] bytes = new byte[readBuffer.remaining()];readBuffer.get(bytes);String body = new String(bytes, "utf-8");System.out.println("The time server receive order :"+body);String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body)?new java.util.Date(System.currentTimeMillis()).toString():"BAD ORDER";doWrite(sc,currentTime);}else if(readBytes<0){//对端关闭连接key.channel();sc.close();}else {;//读到0字节,忽略}}}}private void doWrite(SocketChannel channel, String response) throws IOException {if(response!=null&&response.trim().length()>0){byte[] bytes = response.getBytes();ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);writeBuffer.put(bytes);writeBuffer.flip();channel.write(writeBuffer);}}}
NIO客户端代码:
public class TimeClient { public static void main(String[] args) { int port = 9090; if(args!=null&&args.length>0){ try{ port = Integer.valueOf(args[0]); }catch(NumberFormatException e){ //采用默认值 } } new Thread(new TimeClientHandle("127.0.0.1",port),"TimeClient-001").start(); }}
public class TimeClientHandle implements Runnable{ private String host; private int port; private Selector selector; private SocketChannel socketChannel; private volatile boolean stop; public TimeClientHandle(String host,int port){ this.host = host==null?"127.0.0.1":host; this.port = port; try { selector = Selector.open(); socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); }catch (IOException e){ e.printStackTrace(); System.exit(1); } } @Override public void run() { try { doConnect(); }catch (IOException e){ e.printStackTrace(); System.exit(1); } while (!stop){ try{ selector.select(1000); Set<SelectionKey> selectionKey = selector.selectedKeys(); Iterator<SelectionKey> it = selectionKey.iterator(); SelectionKey key = null; while (it.hasNext()){ key = it.next(); it.remove(); try { handleInput(key); }catch (Exception e){ if(key!=null){ key.cancel(); if (key.channel()!=null) key.channel().close(); } } } }catch (Exception e){ e.printStackTrace(); System.exit(1); } } /** * 多路复用器关闭后,所有注册在上面的Channel和Pipe等资源都会被自动去注册 并关闭,所以不需要重复释放资源 */ if (selector != null) { try { selector.close(); } catch (IOException e) { e.printStackTrace(); } } } private void handleInput(SelectionKey key) throws IOException{ if (key.isValid()){ //判断是否连接成功 SocketChannel sc = (SocketChannel) key.channel(); if (key.isConnectable()) { System.out.println("连接成功..."); if (sc.finishConnect()) { sc.register(selector, SelectionKey.OP_READ); doWrite(sc); } else System.exit(1); } if (key.isReadable()){ ByteBuffer readBuffer = ByteBuffer.allocate(1024); int readBytes = sc.read(readBuffer); if (readBytes>0){ readBuffer.flip(); byte[] bytes = new byte[readBuffer.remaining()]; readBuffer.get(bytes); String body = new String(bytes,"UTF-8"); System.out.println("Now is :"+body); this.stop = true; }else if(readBytes<0){ //对端链路关闭 key.channel(); sc.close(); }else ; //读到0字节,忽略 } } } private void doConnect() throws IOException{ //如果连接成功,则注册到多路复用器上,发送请求消息,读应答 if(socketChannel.connect(new InetSocketAddress(host,port))){ socketChannel.register(selector,SelectionKey.OP_READ); doWrite(socketChannel); }else socketChannel.register(selector,SelectionKey.OP_CONNECT); } private void doWrite(SocketChannel sc) throws IOException{ byte[] req = "QUERY TIME ORDER".getBytes(); ByteBuffer writeBuffer = ByteBuffer.allocate(req.length); writeBuffer.put(req); writeBuffer.flip(); sc.write(writeBuffer); if(!writeBuffer.hasRemaining()){ System.out.println("Send order 2 server succeed."); } }}
阅读全文
0 0
- NIO编程
- NIO编程
- NIO编程
- NIO编程
- Java NIO TCP编程
- Java NIO编程关注点
- NIO的Socket编程
- java nio编程细节
- nio高并发编程
- Java 网络编程nio
- Java NIO 网络编程
- Java NIO编程
- Java高级编程-NIO
- nio高并发编程
- Java NIO 编程总结
- java NIO 网络编程
- NIO编程 TimeServer && TimeClient
- Java NIO网络编程
- 数字系统设计中形式验证
- objc
- 算法学习笔记--4. 二进制求和
- OpenRecon中build运行出错的解决办法
- 多线程实现图片移动
- NIO编程
- java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to
- Android sensorservice
- js闭包
- ORACLE 数据库 学习第一天
- BZOJ 2223 [Coci 2009]PATULJCI 主席树
- 课时23 YUM软件管理
- [东师培训D3T2] Number
- C Looooops POJ