Selector和非阻塞网络编程

传统的 网络编程

​ TCP ServerSocket Socket (阻塞式)

​ UDP DatagramSocket DatagramPacket

1 ServerSocketChannel、SocketChannel实现阻塞式网络编程

ServerSocketChannel是一个基于通道的socket监听器,等同于ServerSocket类。SocketChannel是一个基于通道的客户端套接字,等同于Socket类。

public static void main(String[] args) throws IOException {
        ServerSocketChannel listener=ServerSocketChannel.open();
        //绑定地址
        listener.bind(new InetSocketAddress("127.0.0.1", 8888));
        System.out.println("服务器已启动");
        //监听
        SocketChannel channel = listener.accept();
        //创建缓冲区
        ByteBuffer buffer=ByteBuffer.allocate(1024);
        int len = channel.read(buffer);
        //切换读模式
        buffer.flip();
        String data=new String(buffer.array(), 0, len);
        System.out.println(data);
        channel.close();
    }
  public static void main(String[] args) throws IOException {
        SocketChannel sc=SocketChannel.open(new InetSocketAddress("127.0.0.1", 8888));
        ByteBuffer buffer=ByteBuffer.allocate(1024);
        buffer.put("好久不见".getBytes());
        buffer.flip();
        sc.write(buffer);
        buffer.clear();
        sc.close();
    }

2.selector简介

要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等。

​ 选择器提供选择执行已经就绪的任务的能力.从底层来看,Selector提供了询问通道是否已经准备好执行每个I/O操作的能力。Selector 允许单线程处理多个Channel。仅用单个线程来处理多个Channels的好处是,只需要更少的线程来处理通道。事实上,可以只用一个线程处理所有的通道,这样会大量的减少线程之间上下文切换的开销。

在这里插入图片描述
在这里插入图片描述

  • 选择器(Selector) :Selector选择器类管理着一个被注册的通道集合的信息和它们的就绪状态。通道是和选择器一起被注册的,并且使用选择器来更新通道的就绪状态。

  • 可选择通道(SelectableChannel):SelectableChannel这个抽象类提供了实现通道的可选择性所需要的公共方法。它是所有支持就绪检查的通道类的父类。因为FileChannel类没有继承SelectableChannel因此是不是可选通道,而所有socket通道都是可选择的,SocketChannel和ServerSocketChannel是SelectableChannel的子类。

  • 选择键(SelectionKey):**选择键封装了特定的通道与特定的选择器的注册关系。选择键对象被SelectableChannel.register()返回并提供一个表示这种注册关系的标记。选择键包含了两个比特集(以整数的形式进行编码),选择键支持四种操作类型:

  • Connect 连接
  • Accept 接受请求
  • Read 读
  • Write 写
    java中定义了四种常量来表示这四种操作类型:
  • SelectionKey.OP_CONNECT
  • SelectionKey.OP_ACCEPT
  • SelectionKey.OP_READ
  • SelectionKey.OP_WRITE

3.实现非阻塞式网络编程

服务端

  public static void main(String[] args) throws IOException {
        ServerSocketChannel ssc=ServerSocketChannel.open();
        //设置为非阻塞式
        ssc.configureBlocking(false);
        //绑定ip地址、端口号
        ssc.bind(new InetSocketAddress("127.0.0.1", 9999));
        //创建Selector(轮询器)
        Selector selector=Selector.open();
        //注册选择器
        ssc.register(selector, SelectionKey.OP_ACCEPT);
        while(selector.select()>0){
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()){
                SelectionKey selectionKey = iterator.next();
                if(selectionKey.isAcceptable()){  //测试通道是否可以接收Socket连接
                    SocketChannel accept = ssc.accept();
                    accept.configureBlocking(false);
                    accept.register(selector, SelectionKey.OP_READ);
                }else  if(selectionKey.isReadable()){
                    SocketChannel socketChannel=(SocketChannel) selectionKey.channel();
                    ByteBuffer buffer=ByteBuffer.allocate(1024);
                    int len=-1;
                    while ((len=socketChannel.read(buffer))>0){
                        buffer.flip();
                        System.out.println(new String(buffer.array(),0,len));
                        buffer.clear();
                    }
                    if(len==-1)
                        socketChannel.close();
                }
                iterator.remove();
            }
        }
    }

客户端

   public static void main(String[] args) throws IOException {
        SocketChannel sc=SocketChannel.open( new InetSocketAddress(9999));
        sc.configureBlocking(false);
        Selector selector=Selector.open();
        sc.register(selector, SelectionKey.OP_WRITE);
        Scanner input=new Scanner(System.in);
        ByteBuffer buffer=ByteBuffer.allocate(1024);
        while (true){
            System.out.println("请输入消息:");
            String message = input.next();
            buffer.put(message.getBytes());
            buffer.flip();
            sc.write(buffer);
            buffer.clear();
            if(message.equals("拜拜"))
                break;
        }
        sc.close();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值