开发者社区 > 博文 > JAVA NIO之Selector选择器
分享
  • 打开微信扫码分享

  • 点击前往QQ分享

  • 点击前往微博分享

  • 点击复制链接

JAVA NIO之Selector选择器

  • 京东城市JUST团队
  • 2021-01-22
  • IP归属:未知
  • 25920浏览

实现一个基于JAVA NIO的客户端和服务端, 接收用户输入,服务端接收丢弃。
学好Selector,是多路复用的基础。

服务端

import lombok.extern.slf4j.Slf4j;

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;

/**
 * nio discard server
 *
 * @author jimo
 * @version 1.0.0
 * @date 2020/7/12 14:02
 */
@Slf4j
public class NioDiscardServer {

    /**
     * start server
     */
    public static void startServer() throws IOException {
        // 1.获取选择器
        final Selector selector = Selector.open();
        // 2.获取通道
        final ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 3.设置为非阻塞
        serverSocketChannel.configureBlocking(false);
        // 4.绑定连接
        serverSocketChannel.bind(new InetSocketAddress("127.0.0.1", 8080));
        log.info("服务器启动成功");
        // 5.注册通道到选择器,注册“接收新连接”IO事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        // 6.轮询感兴趣的事件
        while (selector.select() > 0) {
            // 7.获取选择键合集
            final Iterator<SelectionKey> selectKeys = selector.selectedKeys().iterator();
            while (selectKeys.hasNext()) {
                // 8.获取单个选择键
                final SelectionKey selectionKey = selectKeys.next();
                // 9.判断key是什么事件
                if (selectionKey.isAcceptable()) {
                    // 10.如果key是“连接就绪”事件,则获取客户端连接
                    final SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    // 11.将该新连接的可读事件,注册到选择器上
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    log.info("接收客户端连接:{}", socketChannel);
                } else if (selectionKey.isReadable()) {
                    // 12.如果是可读事件,则读取数据
                    final SocketChannel channel = (SocketChannel) selectionKey.channel();
                    // 13.读取数据,然后丢弃
                    final ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int len;
                    while ((len = channel.read(buffer)) > 0) {
                        buffer.flip();
                        log.info("接收到客户端数据:{}", new String(buffer.array(), 0, buffer.limit()));
                        buffer.clear();
                    }
                    channel.close();
                }
                // 14.移除选择键
                selectKeys.remove();
            }
        }
        // 15.关闭连接
        serverSocketChannel.close();
    }

    /**
     * main
     */
    public static void main(String[] args) throws IOException {
        startServer();
    }
}

客户端

@Slf4j
public class NioDiscardClient {

    /**
     * start client
     */
    public static void startClient() throws Exception {
        final InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8080);
        // 1.获取通道
        final SocketChannel socketChannel = SocketChannel.open(address);
        // 2.切换为非阻塞状态
        socketChannel.configureBlocking(false);
        // 3.不断自旋,等待连接完成
        while (!socketChannel.finishConnect()) {
            log.info("正在努力连接...");
        }
        log.info("连接服务器成功");
        // 4.分配缓冲区
        final ByteBuffer buffer = ByteBuffer.allocate(1024);
        // 5.接收用户输入
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            final String input = scanner.next();
            if ("bye".equalsIgnoreCase(input)) {
                break;
            }
            buffer.put(input.getBytes());
            buffer.flip();
            // 发送到服务器
            socketChannel.write(buffer);
            buffer.clear();
        }
        log.info("客户端关闭");
        // 发一个关闭信号
        socketChannel.shutdownOutput();
        socketChannel.close();
    }

    /**
     * main
     */
    public static void main(String[] args) throws Exception {
        startClient();
    }
}

测试

// 客户端(杀掉重启多次,服务端显示的端口不同)
com.jimo.netty.demo.nio.socket.NioDiscardClient 连接服务器成功 
hee
bye
com.jimo.netty.demo.nio.socket.NioDiscardClient 客户端关闭 


// 服务端
com.jimo.netty.demo.nio.socket.NioDiscardServer 服务器启动成功 
com.jimo.netty.demo.nio.socket.NioDiscardServer 接收客户端连接:java.nio.channels.SocketChannel[connected local=/127.0.0.1:8080 remote=/127.0.0.1:53568] 
com.jimo.netty.demo.nio.socket.NioDiscardServer 接收到客户端数据:hee 
com.jimo.netty.demo.nio.socket.NioDiscardServer 接收客户端连接:java.nio.channels.SocketChannel[connected local=/127.0.0.1:8080 remote=/127.0.0.1:53879] 
com.jimo.netty.demo.nio.socket.NioDiscardServer 接收到客户端数据:hehe 
共0条评论