zoukankan      html  css  js  c++  java
  • 6.案例

        1. 目标
        利用Selector+channel+Buffer实现 少量线程处理多个客户端请求
        2. 客户端
        package cn.tedu.nio.selector;
            
        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;
        
        public class SocketChannelDemo01 {
            public static void main(String[] args) throws Exception {
                //0.创建选择器
                Selector selc = Selector.open();
                //1.创建SocketChannel
                SocketChannel sc = SocketChannel.open();
                //2.设定非阻塞模式
                sc.configureBlocking(false);
                //3.连接服务端
                sc.connect(new InetSocketAddress("127.0.0.1", 44444));
                sc.register(selc, SelectionKey.OP_CONNECT);
                
                //4.通过选择器实行选择操作
                while(true){
                    selc.select();//选择器尝试选择就绪的键 选不到就阻塞 选择到就返回就绪的键的数量
                    
                    //5.得到并遍历就绪的键们
                    Set<SelectionKey> keys = selc.selectedKeys();
                    Iterator<SelectionKey> it = keys.iterator();
                    while(it.hasNext()){
                        //6.得到每一个就绪的键
                        SelectionKey key = it.next();
                        //7.获取就绪的键 对应的 操作 和 通道
                        if(key.isAcceptable()){
                            
                        }else if(key.isConnectable()){
                            //--是通道的Connect操作
                            //--获取通道
                            SocketChannel scx = (SocketChannel) key.channel();
                            //--完成连接
                            if(!scx.isConnected()){
                                while(!scx.finishConnect()){};
                            }
                            //--将通道再次注册到selc中 关注WRITE操作
                            scx.register(selc, SelectionKey.OP_WRITE);
                        }else if(key.isReadable()){
                            
                        }else if(key.isWritable()){
                            //--发现是Write操作就绪
                            //--获取通道
                            SocketChannel scx = (SocketChannel) key.channel();
                            //--写出数据
                            ByteBuffer buf = ByteBuffer.wrap("hello nio~ hello java~".getBytes());
                            while(buf.hasRemaining()){
                                scx.write(buf);
                            }
                            //--取消掉当前通道 在选择器中的注册 放置重复写出
                            key.cancel();
                        }else{
                            throw new RuntimeException("未知的键,见了鬼了~");
                        }
                        //8.移除就绪键
                        it.remove();
                    }
                }
            }
        }
            
        3. 服务端
        package cn.tedu.nio.selector;
        
        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 ServerSocketDemo01 {
            public static void main(String[] args) throws Exception {
                //0.创建选择器
                Selector selc = Selector.open();
                //1.创建代表服务器的ServerSocketChannel对象
                ServerSocketChannel ssc = ServerSocketChannel.open();
                //2.设置为非阻塞模式
                ssc.configureBlocking(false);
                //3.设置监听的端口
                ssc.bind(new InetSocketAddress(44444));
                //4.将ssc注册到选择器中关注ACCEPT操作
                ssc.register(selc, SelectionKey.OP_ACCEPT);
                
                //5.通过选择器选择就绪的键
                while(true){
                    selc.select();//尝试到注册的键集中来寻找就绪的键 如果一个就绪的键都找不到 就进入阻塞 直到找到就绪的键 返回就绪的键的个数
                    
                    //6.获取就绪的键的集合
                    Set<SelectionKey> keys = selc.selectedKeys();
                    
                    //7.遍历处理就绪的键 代表的操作
                    Iterator<SelectionKey> it = keys.iterator();
                    while(it.hasNext()){
                        //--获取到就绪的键 根据键代表的操作的不同 来进行不同处理
                        SelectionKey key = it.next();
                        
                        if(key.isAcceptable()){
                            //--发现了Accept操作 
                            //--获取通道
                            ServerSocketChannel sscx = (ServerSocketChannel) key.channel();
                            //--完成Accept操作
                            SocketChannel sc = sscx.accept();
                            //--在sc上注册读数据的操作
                            sc.configureBlocking(false);
                            sc.register(selc, SelectionKey.OP_READ);
                        }else if(key.isConnectable()){
                            
                        }else if(key.isWritable()){
                            
                        }else if(key.isReadable()){
                            //--发现了Read操作
                            //--获取就绪的通道
                            SocketChannel scx = (SocketChannel) key.channel();
                            //--完成读取数据的操作
                            ByteBuffer buf = ByteBuffer.allocate(10);
                            while(buf.hasRemaining()){
                                scx.read(buf);
                            }
                            String msg = new String(buf.array());
                            System.out.println("[收到来自客户端的消息]:"+msg);
                        }else{
                            throw new RuntimeException("未知的键,见了鬼了~");
                        }
                        
                        //8.移除处理完的键
                        it.remove();
                    }
                }
            }
        }

    尽早把自己的生活折腾成自己想要的样子
  • 相关阅读:
    项目中常用的图片处理方案小结
    Unity2D实现人物三连击
    使用mescroll实现上拉加载与下拉刷新
    iOS中文输入法多次触发的问题及解决方案
    使用WebStorm将项目部署到IIS
    在Less中使用条件判断
    Vue+原生App混合开发手记#1
    在Vue中使用layer.js弹出层插件
    局域网简单的SVN服务器的搭建
    在iOS中实现sticky header
  • 原文地址:https://www.cnblogs.com/v-lcc/p/9704756.html
Copyright © 2011-2022 走看看