马士兵教育周老师透彻的讲select多路复用器(单线程)----目标netty---step3

///
【Netty】尚硅谷2019年Netty教程
https://www.bilibili.com/video/BV1jK4y1s7GV?p=24
第24课nio快速入门(1) —讲了nio server 端的写法,共30分钟
(注意,代码处 少了 socketChannel 配置 blocking false 的配置,在下一个视频中介绍了 )
可以先看这个

https://www.bilibili.com/video/BV1jK4y1s7GV?p=25
第24课nio快速入门(1) —讲了nio client 端的写法,并联合调试server client ,共15分钟

///

https://www.bilibili.com/video/BV1ft4y1i7G1?p=16

马士兵教育 周老师,讲的 多路复用select 单线程版本
次代码并非完全的默写, 分5段默写吧,
可以结合
https://www.bilibili.com/video/BV1ft4y1i7G1?p=15
的后10 分钟,一起看关于多路复用器select 的讲解,
***15 此后10分钟讲的是理论
***16 是讲的代码

注意,周老师讲的最后10分钟 关于 client.read(byteBuffer)==-1 ; 也就是端口断开连接,可以忽略不看

package com.tiza.leo.Select;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
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;

/**
 * Author: tz_wl
 * Date: 2020/9/16 23:46
 * Content:  本示例为 select 单线程版本
 */
public class select01single {

    //step 01  初始化全局变量  select  server  port
    private ServerSocketChannel server=null;
    private Selector selector =null;
    private int port =8092;

    //step 02  initServer  实例化 server  selector  并将server注册到select的op_accept上面
    private void initServer() throws IOException {
        server = ServerSocketChannel.open();
        server.bind(new InetSocketAddress(port));
        server.configureBlocking(false);

        selector = Selector.open();
        server.register(selector, SelectionKey.OP_ACCEPT);//服务端的accept注册到selector
    }

    //step 03  start
    // while (true)  {  while(select.select(0)>0) {  //当有02步骤的服务端注册到select  ,
    // 取出  所有的 selectionKeys
    private void start() throws IOException {
        initServer();
        System.out.println("端口号为:"+ port +" ,服务正在启动中... ");
        while (true){
            //如果selector中有值,说明 server 端有 accept事件到达 select
            while (selector.select(0)>0){
                Set<SelectionKey> keySets = selector.selectedKeys();
                Iterator<SelectionKey> iter = keySets.iterator();

                while(iter.hasNext()){
                    SelectionKey key = iter.next();
                    iter.remove();
                    if(key.isAcceptable()){  //如果select 是服务端触发的accept
                        acceptHandler(key);
                    }else if(key.isReadable()){ //如果 select 是客户端触发的 readable
                        readHandler(key);
                    }
                }
            }
        }
    }


    //04 acceptable
    // 当服务端有客户端连接 即是有 accetable 事件 , 注册 客户端的事件 到 select (顺带注册一个byteBuffer空间)
    // 通过   SelectionKey 获取 serverSocketChannel
    // 配置此serverSocketChannel的客户端socketChannel为非阻塞状态
    // 将socketChannel注册为 select 的 readable 并附赠 byteBuffer
    private void acceptHandler(SelectionKey key) throws IOException {
        ServerSocketChannel ssc = (ServerSocketChannel)key.channel();
        SocketChannel clientChannel = ssc.accept();
        clientChannel.configureBlocking(false);
        ByteBuffer byteBuffer = ByteBuffer.allocate(20000);//注册此处在堆分配内存,不是栈
        clientChannel.register(selector,SelectionKey.OP_READ,byteBuffer);
        System.out.println("----------------------------------");
        System.out.println("新客户端"+clientChannel.getRemoteAddress());
        System.out.println("----------------------------------");
    }


    //05 处理客户端readable事件
    private void readHandler(SelectionKey key)  {
        SocketChannel client = (SocketChannel)key.channel();
        ByteBuffer byteBuffer = (ByteBuffer)key.attachment();
        byteBuffer.clear();
        int count=0; //socketChannel中获取到的个数

        try {
            while (true) {
                count = client.read(byteBuffer);
                if (count > 0) {  // 如果能够读到 客户端 的值  ,将此值 会写给客户端
                    byteBuffer.flip();
                    while (byteBuffer.hasRemaining()) {
                        client.write(byteBuffer);
                    }
                    byteBuffer.clear();      //打扫卫生
                } else if (count == 0) {         //如果读不到值 ,停止当前循环
                    break;
                } else {                       //如果是-1 也就是客户端不连接了 , 关闭当前客户端
                    System.out.println(" 客户端断开连接 "+ client.getRemoteAddress());
                    client.close();
                    break;
                }
            }
        }catch (IOException ex){
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        select01single select01single = new select01single();
        select01single.start();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值