博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
9、NIO--阻塞式
阅读量:5956 次
发布时间:2019-06-19

本文共 7710 字,大约阅读时间需要 25 分钟。

 

使用NIO完成网络通信的三个核心:

1、通道(Channel):负责连接

  java.nio.channels.Channel接口:

    SelectableChannel抽象类:有一下几个实现类

      SocketChannel      TCP

      ServerSocketChannel  TCP

      DategramChannel      UDP

      Pipe.SinkChannel

      Pipe.SourceChannel

 

2、缓冲区(Buffer):负责数据的存取

3、选择器(Selector):式SelectableChannel的多路复用器,用于监控SelectableChannel的IO状况

 

代码实例:

//服务端    @Test    public void server() throws IOException{                //1、获取异常        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();                //2、绑定连接        serverSocketChannel.bind(new InetSocketAddress(8081));            //3、获取客户端连接的通道        SocketChannel sockChannel = serverSocketChannel.accept();                //4、分配指定大小的缓冲区        ByteBuffer buf = ByteBuffer.allocate(1024);                //5、接收客户端的数据保存到本地        FileChannel outChannel = FileChannel.open(Paths.get("d:\\aaa.jpg"), StandardOpenOption.WRITE                            ,StandardOpenOption.CREATE,StandardOpenOption.READ);                while(sockChannel.read(buf) != -1){            buf.flip();            outChannel.write(buf);            buf.clear();        }                serverSocketChannel.close();        outChannel.close();        sockChannel.close();     }

 

//客户端    @Test    public void client(){                //1、获取通道        SocketChannel socketChannel = null;                FileChannel inChannel = null;        try {            socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8081));                        //2、分配指定大小的缓冲区            ByteBuffer buf = ByteBuffer.allocate(1024);                        //3、读取本地文件,并且发送            inChannel = FileChannel.open(Paths.get("d:\\a.jpg"), StandardOpenOption.READ);                        while(inChannel.read(buf) != -1){                buf.flip();                socketChannel.write(buf);                buf.clear();            }        } catch (IOException e) {            e.printStackTrace();        }finally {                try {                    socketChannel.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }                try {                    inChannel.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }        }    }

先开启服务端在开启客户端:

 

 

阻塞式测试:(服务端给客户端回复响应信息)

@Test    public void server() throws IOException{                //1、获取异常        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();                //2、绑定连接        serverSocketChannel.bind(new InetSocketAddress(8081));            //3、获取客户端连接的通道        SocketChannel sockChannel = serverSocketChannel.accept();                //4、分配指定大小的缓冲区        ByteBuffer buf = ByteBuffer.allocate(1024);                //5、接收客户端的数据保存到本地        FileChannel outChannel = FileChannel.open(Paths.get("d:\\aaaa.jpg"), StandardOpenOption.WRITE                            ,StandardOpenOption.CREATE,StandardOpenOption.READ);                while(sockChannel.read(buf) != -1){            buf.flip();            outChannel.write(buf);            buf.clear();        }                //发送反馈信息        buf.put("服务端接收图片成功".getBytes());        buf.flip();        sockChannel.write(buf);                serverSocketChannel.close();        outChannel.close();        sockChannel.close();    }

 

客户端:

//客户端    @Test    public void client(){        //1、获取通道        SocketChannel socketChannel = null;        FileChannel inChannel = null;        try {            socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8081));                        //2、分配指定大小的缓冲区            ByteBuffer buf = ByteBuffer.allocate(1024);                        //3、读取本地文件,并且发送            inChannel = FileChannel.open(Paths.get("d:\\a.jpg"), StandardOpenOption.READ);                        while(inChannel.read(buf) != -1){                buf.flip();                socketChannel.write(buf);                buf.clear();            }                        //接收服务端的反馈            int len = 0;            while((len = socketChannel.read(buf)) != -1){                buf.flip();                System.out.println(new String(buf.array(),0,len));                buf.clear();            }                    } catch (IOException e) {            e.printStackTrace();        }finally {                try {                    socketChannel.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }                try {                    inChannel.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }        }    }

此时运行服务端和客户端

会发现处于阻塞状态

并无相关的信息进行打印

 

此时的解决方案:客户端告诉服务端我已经发送数据完成:

在客户端中进行添加代码:

//3、读取本地文件,并且发送            inChannel = FileChannel.open(Paths.get("d:\\a.jpg"), StandardOpenOption.READ);                        while(inChannel.read(buf) != -1){                buf.flip();                socketChannel.write(buf);                buf.clear();            }            //告诉服务端数据已发送            socketChannel.shutdownOutput();

 此时是可以接收到服务端的反馈信息

 

非阻塞式

服务端:

//服务端    @Test    public void server() throws IOException{        //1、获取通道        ServerSocketChannel ssChannel = ServerSocketChannel.open();                //2、切换非阻塞模式        ssChannel.configureBlocking(false);                //3、绑定连接        ssChannel.bind(new InetSocketAddress(8081));                //4、获取选择器        Selector selector = Selector.open();                //5、将通道注册到选择器上,指定监听事件        //SelectionKey.OP_ACCEPT:接收        ssChannel.register(selector, SelectionKey.OP_ACCEPT);                //6、轮询式的获取选择器上已经准备就绪的事件        while(selector.select() > 0){            //7、获取当前选择器中所有注册的“悬着键”            Iterator
it = selector.selectedKeys().iterator(); //8、迭代获取 while(it.hasNext()){ //9、获取准备就绪的事件 SelectionKey sk = it.next(); //10、判断是什么事件准备就绪 if(sk.isAcceptable()){ //接收就绪就获取客户端的连接 SocketChannel sChannel = ssChannel.accept(); //切换非阻塞模式 sChannel.configureBlocking(false); //将该通道注册到选择器上 sChannel.register(selector, SelectionKey.OP_READ); }else if(sk.isReadable()){ //判断是都是读就绪状态 SocketChannel sChannel = (SocketChannel) sk.channel(); //读取数据 ByteBuffer buf = ByteBuffer.allocate(1024); int len = 0; while((len = sChannel.read(buf)) > 0){ buf.flip(); System.out.println(new String(buf.array(),0,len)); buf.clear(); } } } //取消选择键 SelectionKey sk = it.next(); it.remove(); } }

 

 

客户端:

//客户端    @Test    public void client() throws IOException{        //1、获取通道        SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",8081));                //2、切换非阻塞模式        sChannel.configureBlocking(false);                //3、指定大小的缓冲区        ByteBuffer buf = ByteBuffer.allocate(1024);                //4、发送数据给服务端        buf.put(new Date().toString().getBytes());                buf.flip();                sChannel.write(buf);        buf.clear();                //5、关闭通道        sChannel.close();                    }

 

先运行服务端在运行客户端:

 

选择器

 

选择器的应用

 

 

SelectionKey

 

Selector的常用方法

 

 

SocketChannel

 

 

转载于:https://www.cnblogs.com/Mrchengs/p/10836011.html

你可能感兴趣的文章
使用触发器记录oracle用户登陆信息
查看>>
5 kvm虚拟磁盘扩容
查看>>
关于Ubuntu下apt的一些用法及和yum的比较
查看>>
android随机运算器开发小结1
查看>>
Centos 6.5下NIS服务安装配置
查看>>
我的友情链接
查看>>
MediaPlayer的错误修复
查看>>
网络安全之***手法计中计
查看>>
Struts2拦截器的使用 (详解)
查看>>
我的友情链接
查看>>
OEL7.2下Oracle11.2.0.4RAC部署
查看>>
nagios安装与配置
查看>>
RedHat 设置IP、网关、DNS
查看>>
MYSQL 主从复制读写分离实现
查看>>
linux更改语言
查看>>
centos7 修改mac地址
查看>>
<script>标签的加载解析执行
查看>>
恢复rm删除的文件(ext3
查看>>
我的友情链接
查看>>
账户注销完自动登录账户,并且不需要再点击屏幕的账户头像
查看>>