Java NIO 学习
来源:互联网 发布:淘宝卖东西被骗 编辑:程序博客网 时间:2024/06/01 07:51
关于Java NIO 基础,推荐 IBM developerWorks上的一篇文章,写的非常的好,作者是Greg Travis 。
NIO入门
https://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html
NIO Socket Demo
这里贴一个我练习的一个NIO例子,该例子是在阅读学习《Netty权威指南 》这本书参考写的,为的是理解NIO的思想。
关键点我都写在注释中,特别要注意 I/O多路复用模型,把大量的I/O请求连接复用到一个Selector线程中去处理。
以下为例子:
场景:客户端向服务端发送一条请求当前时间的指令,服务端收到指令后返回当前时间给客户端输出。
客户端:TimeClient
服务端:TimeServer
TimeServer
/** * Created by kay on 2017/9/8. */public class TimeServer { public static void main(String[] args) { int port=8888; MultiplexerTimeServer timeServer = new MultiplexerTimeServer(port); new Thread(timeServer,"多路复用TimeServer启动").start(); }}
MultiplexerTimeServer 多路复用类,也就是服务端的处理线程
package com.kay.concurrent.nio.timesocket;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.Date;import java.util.Iterator;import java.util.Set;/** * Created by kay on 2017/9/7. * 多路复用类 * 处理多个客户端的并发请求 * selector 多路复用器 */public class MultiplexerTimeServer implements Runnable{ private Selector selector; private ServerSocketChannel servChannel; private volatile boolean stop; /** * 初始化 绑定注册监听 * @param port */ public MultiplexerTimeServer(int port) { try { selector=Selector.open(); servChannel = ServerSocketChannel.open(); servChannel.configureBlocking(false); //设置非阻塞模式 servChannel.bind(new InetSocketAddress(port)); //绑定端口 servChannel.register(selector, SelectionKey.OP_ACCEPT); //监听准备连接 System.out.println("TimeServer 正在监听端口:"+port); } catch (IOException e) { e.printStackTrace(); //初始化失败则退出,例如端口占用等 System.exit(1); } } @Override public void run() { while (!stop) { try { //每隔一秒 轮询一次 selector.select(1000); Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> it = selectionKeys.iterator(); while (it.hasNext()) { SelectionKey key=it.next(); it.remove(); try { //处理准备好的事件 handleInput(key); } catch (Exception e) { if(key!=null){ key.cancel(); if (key.channel() != null) { key.channel().close(); } } } } } catch (Throwable t) { t.printStackTrace(); } } //关闭多路复用器,绑定在上面的channel也会被自动关闭 if (selector != null) { try { selector.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 统一事件处理,根据key 的类型作出相应处理 * 1.对方请求连接->accept->注册监听对方发的消息 * 2.对方发送消息->读取消息->做出响应 * @param key * @throws IOException */ private void handleInput(SelectionKey key) throws IOException{ //判断是否可用 if (key.isValid()) { //判断是否是accept事件 if (key.isAcceptable()) { //拿到这个key上面绑定的Channel,然后获取对面来的SocketChannel //将这个channel注册 监听它的读事件(因为它已经连接了,所以就等着它发消息了) ServerSocketChannel ssc= (ServerSocketChannel) key.channel(); SocketChannel sc=ssc.accept(); sc.configureBlocking(false); System.out.println("--新请求接入,开始监听它发来的消息..."); sc.register(selector, SelectionKey.OP_READ); } //判断对方是否放消息来了,是就读取消息/作出响应 if (key.isReadable()) { SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer readBuffer = ByteBuffer.allocate(1024); int readBytes = socketChannel.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("Time Server 接收到消息:"+body); String currentTime=""; if ("QUERY_TIME".equals(body)) { currentTime = "现在时间是:" + new Date(System.currentTimeMillis()).toString(); } else { currentTime="指令错误!"; } //作出响应 doWrite(socketChannel,currentTime); } else if (readBytes < 0) { key.cancel(); socketChannel.close(); }else { ;//读到0字节忽略 } } } } //响应消息 private void doWrite(SocketChannel socketChannel, 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(); socketChannel.write(writeBuffer); System.out.println("--已发送响应"); } }}
TimeClient 客户端
/** * Created by kay on 2017/9/8. */public class TimeCient { public static void main(String[] args) { int port=8888; TimeClientHandle clientHandle=new TimeClientHandle("127.0.0.1",port); new Thread(clientHandle,"TimeClient").start(); }}
TimeClientHandle 客户端处理线程
package com.kay.concurrent.nio.timesocket;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.SocketChannel;import java.util.Iterator;import java.util.Set;/** * Created by kay on 2017/9/8. */public class TimeClientHandle implements Runnable { private String host; private int port; private SocketChannel socketChannel; private Selector selector; private volatile boolean stop=false; 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> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> it = selectionKeys.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); } } if (selector != null) { try { selector.close(); } catch (IOException e) { e.printStackTrace(); } } } private void handleInput(SelectionKey key) throws IOException { SocketChannel sc= (SocketChannel) key.channel(); if (key.isConnectable()) { 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("--接收到消息:" + body); this.stop=true; } else if (readBytes < 0) { //对面关掉了链接 key.cancel(); sc.close(); }else ; //没有读到东西 } } private void doConnect() throws IOException { //客户端去连接服务器,如果返回false,则说明发送了syn,但服务器没有响应ack,三次握手没有完成 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".getBytes(); ByteBuffer writeBuffer = ByteBuffer.allocate(req.length); writeBuffer.put(req); writeBuffer.flip(); sc.write(writeBuffer); if (!writeBuffer.hasRemaining()) { System.out.println("指令发送成功!"); } }}
阅读全文
0 0
- java.nio包学习
- Java Nio学习笔记
- java nio 缓冲区学习
- Java之nio学习
- java nio学习
- JAVA NIO学习
- Java NIO 学习
- Java NIO学习
- java NIO 入门学习
- JAVA NIO学习
- Java NIO学习笔记
- Java NIO 学习demo
- java nio学习资料
- java.nio-学习
- java NIO实例学习
- java nio学习(四)
- java NIO 学习笔记
- Java nio学习
- java开发中JDBC连接数据库代码和步骤
- zabbix 批量添加聚合图形
- Python三神器之virtualenv&virtualenvwrapper
- python:3:列表基本用法及相关函数(1)
- json字符串转为map结构,复杂json字符串转为map结构
- Java NIO 学习
- 详细讲解C语言单机小游戏——打字母游戏
- 如何请教别人
- Python常用内置模块总结
- css-day5-个人学习笔记
- [数据结构]二分法查找
- docker构建微服务
- Android 进阶 教你打造 Android 中的 IOC 框架 【ViewInject】 (下)
- 请实现一个函数用来找出字符流中第一个只出现一次的字符