java Nio Demo

来源:互联网 发布:淘宝客服表情包下载 编辑:程序博客网 时间:2024/06/03 18:20

之前的文章主要讲解了Reactor模式、多路复用器select、以及Netty框架,这篇文章主要是java Nio的代码,但我们知道java的Nio是使用了Reactor模式和多路复用器来实现的,所以下面看看java nio的demo。


一、java Nio 客户端

package com.test2;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;public class Client { //多路复用器、选择器(具体看使用的操作系统以及jdk版本,1.5有可能就是select而1.7就是epoll)private Selector selector;public Client init(String serverIp, int port) throws IOException {// 获取socket通道、// 在reactor模式中的资源// select、epoll函数中的fd(个人理解如有错误请求指正)SocketChannel channel = SocketChannel.open();// 将该通道设置为非阻塞channel.configureBlocking(false);// 获取多路复用器实例selector = Selector.open();// 客户端连接服务器,需要调用channel.finishConnect();才能实际完成连接。channel.connect(new InetSocketAddress(serverIp, port));// 为该通道注册SelectionKey.OP_CONNECT事件,也就是将channel的fd和感兴趣的事件添加到多路复用器中channel.register(selector, SelectionKey.OP_CONNECT);return this;}public void listen() throws IOException {System.out.println("客户端启动");// 轮询访问selectorwhile (true) {// 选择注册过的io操作的事件(第一次为SelectionKey.OP_CONNECT)// 看过之前文章的话,就明白这是获取注册到该复用器中的通道的相关事件,获取的过程也就是select()方法遍历获取事件不同的系统、jdk也不同,如果是epoll则是从一个fd就绪队列获取// 而select和poll则是遍历存放channel和事件的集合所以效率低下一些,还有其他的效率问题可以看看之前epoll和select的讲解selector.select();//获取注册在该复用器上的channel和channelEventIterator<SelectionKey> ite = selector.selectedKeys().iterator();while (ite.hasNext()) {SelectionKey key = ite.next();// 删除已选的key,防止重复处理ite.remove();if (key.isConnectable()) {SocketChannel channel = (SocketChannel) key.channel();// 如果正在连接,则完成连接if (channel.isConnectionPending()) {channel.finishConnect();}// channel.configureBlocking(false);// 向服务器发送消息channel.write(ByteBuffer.wrap(new String("send message to server.").getBytes()));// 连接成功后,注册接收服务器消息的事件channel.register(selector, SelectionKey.OP_READ);System.out.println("客户端连接成功");} else if (key.isReadable()) { // 判断该channel的channelEvent事件类型,也就是reactor模式中的分发器,如果把里面处理过程进行封装就是处理器了// 因为selectionKey中存放的是channel和channelEvent所以可以通过selectionKey就能获取channelSocketChannel channel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);channel.read(buffer);byte[] data = buffer.array();String message = new String(data); System.out.println("recevie message from server:, size:" + buffer.position() + " msg: " + message);ByteBuffer outbuffer = ByteBuffer.wrap(("client.".concat(message)).getBytes());channel.write(outbuffer);}}}}public static void main(String[] args) throws IOException {new Client().init("127.0.0.1", 9981).listen();}}

二、java Nio服务端

package com.test2;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;/** * 客户端还是服务端资源、复用器、分发器、处理器整个流程使用都是一样的…… * @author sykj * */public class Server {//多路复用器private Selector selector;public Server init(int port) throws IOException {// 获取一个ServerSocket通道ServerSocketChannel serverChannel = ServerSocketChannel.open();serverChannel.configureBlocking(false);serverChannel.socket().bind(new InetSocketAddress(port));// 获取多路复用器对象selector = Selector.open();// 将通道管理器与通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,// 只有当该事件到达时,Selector.select()会返回,否则一直阻塞。serverChannel.register(selector, SelectionKey.OP_ACCEPT);return this;}public void listen() throws IOException {System.out.println("服务器端启动成功");// 使用轮询访问selectorwhile (true) {selector.select();Iterator<SelectionKey> ite = selector.selectedKeys().iterator();while (ite.hasNext()) {SelectionKey key = ite.next();ite.remove();// 客户端请求连接事件if (key.isAcceptable()) {ServerSocketChannel server = (ServerSocketChannel) key.channel();// 获得客户端连接通道SocketChannel channel = server.accept();channel.configureBlocking(false);// 向客户端发消息channel.write(ByteBuffer.wrap(new String("send message to client").getBytes()));// 在与客户端连接成功后,为客户端通道注册SelectionKey.OP_READ事件。channel.register(selector, SelectionKey.OP_READ);System.out.println("客户端请求连接事件");} else if (key.isReadable()) {// 有可读数据事件// 获取客户端传输数据可读取消息通道。SocketChannel channel = (SocketChannel) key.channel();// 创建读取数据缓冲器ByteBuffer buffer = ByteBuffer.allocate(10);int read = channel.read(buffer);byte[] data = buffer.array();String message = new String(data);ByteBuffer outbuffer = ByteBuffer.wrap(message.getBytes());channel.write(outbuffer);}}}}public static void main(String[] args) throws IOException {new Server().init(9981).listen();}}


OK 有代码有注释应该能看明白,个人感觉javaNio和Reactor模式对应起来理解Reactor 模式还是比较好,Reactor模式是资源、选择器、分发器和处理器这几个模块组成.

在java Nio中个人理解的对应关系:


这就是个人理解,如果感觉不会好过于简单的可以查看前面文章对reactor有详细分析……


java Bio对比java Nio

Bio和Nio底层的实现模型不同,所以区别也就是从这里开始,Bio即阻塞同步IO而Nio即非阻塞同步IO他们最大的区别就是一个是阻塞一个非阻塞的,阻塞非阻塞就是对请求响应的一种形态。在效率问题上的Nio相比Bio最大的区别就是Reactor模式的使用Reactor模式中的多路复用在多并发访问以及高并发访问的情况下有更少的资源消耗,因为就复用器一个线程能管理多个或所有客户端的连接关系,相比一个客户端请求一个线程资源的消耗很小。

Bio的阻塞是在accept阻塞的,而Nio的阻塞是在事件上阻塞的,不是说Nio是非阻塞的吗(那是对客户端请求来说是非阻塞的),而服务端对获取客户端请求的等待是阻塞的。


这么说吧,在服务端获得客户端请求不管是Bio还是Nio都是阻塞的,但他们阻塞的时间地点不同,之后说的所有情况都是在客户端和服务端之间已经成功建立tcp链接。

Bio 每当有请求来的时候都是通过服务端的accept()方法来获取客户端的请求,服务端获取请求后对这个请求进行后续的处理,在将处理结果返回给客户端

而在Nio中(epoll)使用了多路复用器,所以当某个客户端请求来的时候,会把该客户端连接和客户端请求事件保存到 FD事件队列,在程序中轮询select时是对有事件的channel和事件进行了轮询,他的阻塞是在select()时阻塞的,而客户端不用同步等待服务端消息,服务端获得select()中的事件后能立马先给客户端返回一个成功消息,将处理后的信息之后再传过去

Bio 和 Nio服务端阻塞的事件和时间点不同、Bio 和 Nio对客户端的响应也是不同以及对客户端请求事件的轮询查询不同。

总的来说Nio相比Bio消耗资源少,获取客户端请求事件循环的队列小,也就是使用复用器带来的好处,其他的区别……



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 球球大作战找不到团战服务器怎么办 小孩的腰有点弯怎么办 小朋友不听话被老师罚站怎么办 幼儿园小朋友被老师罚站怎么办 生完小孩弯腰驼背怎么办 小孩爱捡垃圾是怎么办 腰扭了不敢弯腰怎么办 小人狗在背后骂我怎么办 微信表情缺失了怎么办 动图过大 微信 怎么办 我能怎么办图片带字 我该怎么办图片带字 学化妆找不到模特练妆怎么办? cf进房间闪退怎么办 手游cf账号封了怎么办 大门牙缺了一块怎么办 缺了一颗牙齿怎么办 CF购买医疗包竞猜币没到账怎么办 CF手游昵称不合法怎么办 微信gif尺寸过大怎么办 微信表情上限300怎么办 太受欢迎了怎么办快穿 兔宝宝沾上人气味怎么办 我该怎么办的文字图片 爱奇艺缓存视频显示下载失败怎么办 把老公惹生气了怎么办 苹果x用电量太快怎么办 小中考地生没过怎么办 如果遇到不负责的语文老师怎么办 孩子的语文老师教的不好怎么办 刚买的小猫很凶怎么办 2月幼犬不吃东西怎么办 小狗狗不吃狗粮怎么办 母猫不会照顾小猫怎么办 刚买的小狗拉稀怎么办 母兔子吃小兔子怎么办 照片照出来背亮景人是黑的怎么办 手机透明壳变黄了怎么办 ae视频渲染太慢怎么办 3ce口红太干了怎么办 中考误用0.38mm的笔怎么办