javaNIO
来源:互联网 发布:mahout聚类算法实现 编辑:程序博客网 时间:2024/05/20 19:18
说明: 用语言描述下nio
server 端得到一个selector binding到了 serverchannel并给它(强调 serverchannel)注册了 ACCEPTABLE 事件
client 端一样得到一个selector binding到了 socketchannel 并给它(强调socketchannel)注册了CONNECTED 事件
两边一联 各自触发了 ACCEPTABLE 事件(服务端) 和 CONNECTED 事件(客户端) 并各自拿到了 SelectionKey
再通过SelectionKey 得到 socketchannel(强调注意 是socketchannel) 并channel.register(this.selector, SelectionKey.OP_READ); 注册上selector 和 添加 READ事件
之后每次socketchannel.write(outBuffer) 都会给对方的selector 一个READ事件,对方通过selectionkey 并识别是READ事件后, 可以从selectionkey 拿到对应的socketchannel
然后 读 和写 数据
refer to http://weixiaolu.iteye.com/blog/1479656 (following is modified by this article)
server 端代码
package cn.nio;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; /** * NIO服务端 * @author 小路 */ public class NIOServer { //通道管理器 private Selector selector; /** * 获得一个ServerSocket通道,并对该通道做一些初始化的工作 * @param port 绑定的端口号 * @throws IOException */ public void initServer(int port) throws IOException { // 获得一个ServerSocket通道 ServerSocketChannel serverChannel = ServerSocketChannel.open(); // 设置通道为非阻塞 serverChannel.configureBlocking(false); // 将该通道对应的ServerSocket绑定到port端口 serverChannel.socket().bind(new InetSocketAddress(port)); // 获得一个通道管理器 this.selector = Selector.open(); //将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后, //当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。 serverChannel.register(selector, SelectionKey.OP_ACCEPT); } /** * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理 * @throws IOException * @throws InterruptedException */ // FYI 这里没用到 @SuppressWarnings("unchecked") public void listen() throws IOException, InterruptedException { System.out.println("服务端启动成功!"); // 轮询访问selector while (true) { /*try {Thread.sleep(500);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}*/ //当注册的事件到达时,方法返回;否则,该方法会一直阻塞 selector.select(); // 获得selector中选中的项的迭代器,选中的项为注册的事件 Iterator ite = this.selector.selectedKeys().iterator(); while (ite.hasNext()) { SelectionKey key = (SelectionKey) ite.next(); // 删除已选的key,以防重复处理 ite.remove(); // 客户端请求连接事件 if (key.isAcceptable()) { ServerSocketChannel server = (ServerSocketChannel) key .channel(); System.out.println("debug1:" +server.socket().getLocalPort()); try {Thread.sleep(500000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} // 获得和客户端连接的通道 SocketChannel channel = server.accept(); // 设置成非阻塞 channel.configureBlocking(false); //在这里可以给客户端发送信息哦 //channel.write(ByteBuffer.wrap(new String("hello chickens").getBytes())); //在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。 //channel.register(this.selector, SelectionKey.OP_READ); // 获得了可读的事件 } else if (key.isReadable()) { System.out.println("readable"); read(key); } } } } /** * 处理读取客户端发来的信息 的事件 * @param key * @throws IOException */ public void read(SelectionKey key) throws IOException{ // 服务器可读取消息:得到事件发生的Socket通道 SocketChannel channel = (SocketChannel) key.channel(); // 创建读取的缓冲区 System.out.println("debug2:" +channel.socket().getLocalPort()); ByteBuffer buffer = ByteBuffer.allocate(10); channel.read(buffer); byte[] data = buffer.array(); String msg = new String(data).trim(); System.out.println("服务端收到信息:"+msg); ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes()); channel.write(outBuffer);// 将消息回送给客户端 } /** * 启动服务端测试 * @throws IOException * @throws InterruptedException */ public static void main(String[] args) throws IOException, InterruptedException { NIOServer server = new NIOServer(); server.initServer(8000); //server.listen(); while(true){ System.out.println("select " + server.selector.select() + "event"); Iterator ite = server.selector.selectedKeys().iterator(); Thread.sleep(5000); while (ite.hasNext()) { SelectionKey key = (SelectionKey) ite.next(); // 删除已选的key,以防重复处理 ite.remove(); // 客户端请求连接事件 if (key.isAcceptable()) { System.out.println("ssssssssss"); //Thread.sleep(5000000); System.out.println("yyyyy"); ServerSocketChannel serverch = (ServerSocketChannel) key .channel(); // 获得和客户端连接的通道 SocketChannel channel = serverch.accept(); // 设置成非阻塞 System.out.println("debug1:" +channel.socket().getPort()); channel.configureBlocking(false); String msg = "first sendmsg to client"; ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes()); channel.write(outBuffer);// 将消息回送给客户端 Thread.sleep(5000); String msgs = "second sendmsg to client"; ByteBuffer outBuffers = ByteBuffer.wrap(msgs.getBytes()); channel.write(outBuffers);// 将消息回送给客户端 } } } //在这里可以给客户端发送信息哦 //channel.write(ByteBuffer.wrap(new String("hello chickens").getBytes())); //在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。 //channel.register(this.selector, SelectionKey.OP_READ); } }
client端
package cn.nio;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;/** * NIO客户端 * * @author 小路 */public class NIOClient {// 通道管理器private Selector selector;/** * 获得一个Socket通道,并对该通道做一些初始化的工作 * * @param ip * 连接的服务器的ip * @param port * 连接的服务器的端口号 * @throws IOException */public void initClient(String ip, int port) throws IOException {// 获得一个Socket通道SocketChannel channel = SocketChannel.open();// 设置通道为非阻塞channel.configureBlocking(false);// 获得一个通道管理器this.selector = Selector.open();// 客户端连接服务器,其实方法执行并没有实现连接,需要在listen()方法中调,用channel.finishConnect();才能完成连接,才能将 select的connect事件消化,否则会//一直返回1,且状态属于updatedchannel.connect(new InetSocketAddress(ip, port));// 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_CONNECT事件。channel.register(selector, SelectionKey.OP_CONNECT);}/** * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理 * * @throws IOException */@SuppressWarnings("unchecked")public void listen() throws IOException {// 轮询访问selectorint i = 0;while (true) {/* * try { Thread.sleep(5000000); } catch (InterruptedException e) { * // TODO Auto-generated catch block e.printStackTrace(); } */selector.select();// 获得selector中选中的项的迭代器Iterator ite = this.selector.selectedKeys().iterator();while (ite.hasNext()) {System.out.println("debug3");SelectionKey key = (SelectionKey) ite.next();// 删除已选的key,以防重复处理ite.remove();// 连接事件发生if (key.isConnectable()) {System.out.println("confirm server has connected me");/* * try { Thread.sleep(500000); } catch (InterruptedException * e) { // TODO Auto-generated catch block * e.printStackTrace(); } SocketChannel channel = * (SocketChannel) key.channel(); // 如果正在连接,则完成连接 if * (channel.isConnectionPending()) { * channel.finishConnect(); * * } // 设置成非阻塞 channel.configureBlocking(false); * System.out.println("debug4"); * * //break; // 在这里可以给服务端发送信息哦 * channel.write(ByteBuffer.wrap(new String("向服务端发送了一条信息") * .getBytes())); * * // 在和服务端连接成功之后,为了可以接收到服务端的信息,需要给通道设置读的权限。 * channel.register(this.selector, SelectionKey.OP_READ); * * // 获得了可读的事件 */} else if (key.isReadable()) {read(key);}}}}/** * 处理读取服务端发来的信息 的事件 * * @param key * @throws IOException */public void read(SelectionKey key) throws IOException {// 和服务端的read方法一样SocketChannel channel = (SocketChannel) key.channel();// 创建读取的缓冲区ByteBuffer buffer = ByteBuffer.allocate(10);channel.read(buffer);byte[] data = buffer.array();String msg = new String(data).trim();System.out.println("client收到信息:" + msg);ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());channel.write(outBuffer);// 将消息回送给客户端}/** * 启动客户端测试 * * @throws IOException * @throws InterruptedException */public static void main(String[] args) throws IOException,InterruptedException {NIOClient client = new NIOClient();client.initClient("localhost", 8000);while (true) {System.out.println("clientselect " + client.selector.select()+ "event");Iterator ite = client.selector.selectedKeys().iterator();while (ite.hasNext()) {SelectionKey key = (SelectionKey) ite.next();// 删除已选的key,以防重复处理ite.remove();// 客户端请求连接事件Thread.sleep(1000);if (key.isConnectable()) {System.out.println("connectable event");SocketChannel channel = (SocketChannel) key.channel();// 如果正在连接,则完成连接if (channel.isConnectionPending()) {channel.finishConnect();channel.register(client.selector, SelectionKey.OP_READ);// 加了一个稳定的注册时间它就不返回0了}// System.out.println("debug1:"// +channel.socket().getLocalPort());// 获得和客户端连接的通道// SocketChannel channel = serverch.accept();// 设置成非阻塞// channel.configureBlocking(false);} else if (key.isReadable()) {SocketChannel channel = (SocketChannel) key.channel();// 创建读取的缓冲区ByteBuffer buffer = ByteBuffer.allocate(1010);channel.read(buffer);byte[] data = buffer.array();String msg = new String(data).trim();System.out.println("client收到信息:" + msg);}}}// client.listen();}}
client输出:
clientselect 1event
connectable event
clientselect 1event
client收到信息:first sendmsg to client
clientselect 1event
client收到信息:second sendmsg to client
server输出:
select 1event
ssssssssss
yyyyy
debug1:59956
NIO的WRTIE事件
简单说 防止客户端(应该说接受方) 因网络问题等,无法接受发送方的消息,导致发送方while true 空循环 大量消耗cpu资源
java nio对OP_WRITE的处理解决网速慢的连接 refer to http://blog.sina.com.cn/s/blog_783ede0301013g5n.html
(2012-05-17 17:12:50)java
nio
it
分类:JavaNIO- javaNIO
- JavaNIO
- javaNIO
- JavaNIO
- JavaNIO整理
- javaNIO操作
- javaNIO学习
- JavaNIO:Buffer
- javanio学习
- javaNIO使用
- javaNIO笔记一
- javaNIO笔记二
- javaNIO笔记三
- javanio 实现socket通信
- javaNIO之Scatter/Gather
- javaNIO之选择器
- javaNIO(转载)
- JavaNio——Channel
- python watchdog:监控文件系统事件的Python库
- 权限控制中间件
- c++如何分割带有逗号的字符串
- GLSL内建函数详解
- xxxTests-Info.plist Error in Xcode(删除test target)
- javaNIO
- Hello World
- ios逆向工程-静态分析
- [Ugirls爱尤物] No.037 赵伊彤 喜欢吗?喜欢就告诉她!
- HASH表的模板实现
- TCP HTTP 与 SOCKET
- Library get data from a sample module through a control board
- coj 1259: 跳跳
- 链表求和