我的Java学习之路(13)-- Java NIO网络编程制作简易聊天室

一、NIO简介

  • NIO全称:Non-blocking IO 或 New IO,是非阻塞式的IO
  • JDK版本:JDK1.4+
  • 应用场景:高并发网络服务编程

二、编程模型

  • 模型:对事物共性的抽象
  • 编程模型:对编程共性的抽象

三、BIO网络模型

  1. BIO网络模型介绍
    在这里插入图片描述
    从图中可以看出,一个线程到第5步的时候,会阻塞在那等待客户端的下次请求,每新增一个客户端,就会启动一个新的线程来处理这个客户端的请求,如果客户端量很大的话,就会造成服务器压力过大而崩溃。

  2. BIO网络模型缺点

  • 阻塞式IO模型
  • 弹性伸缩能力差
  • 多线程非常消耗资源

四、NIO网络模型

  1. NIO网络模型介绍
    在这里插入图片描述
    相对于BIO,NIO的网络模型就要复杂的多,服务端提供一个单线程的Selector组件,它是一个事件注册监听器,负责监听管理注册到它上面的连接和事件,但是本身不负责处理客户端的业务逻辑。当它监听到指定的事件,就会启动相应的事件处理器去处理请求,事件处理器可以依次处理多个请求,处理完成之后,由事件处理器去响应客户端,Selector本身继续监听其他事件。

  2. NIO模型的优点

  • 非阻塞式IO模型
  • 弹性伸缩能力强
  • 单线程节约资源
  1. 原生NIO的缺点
  • NIO类库和API比较复杂
  • 可靠性能力补齐,工作量和难度都非常大
  • Selector空轮询,导致CPU占用100%的bug还没有修复

五、具体代码实现

  1. 服务端代码NioServer.java
package com.feonix;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * NIO服务器端
 */
public class NioServer {
   
    /**
     * 映射客户端channel
     */
    private Map<String, SocketChannel> clientsMap = new HashMap<String, SocketChannel>();

    public static void main(String[] args) {
   
        NioServer nioServer = new NioServer();
        try {
   
            // 启动服务端
            nioServer.start();
        } catch (IOException e) {
   
            e.printStackTrace();
        }
    }

    /**
     * 启动
     *
     * @throws IOException
     */
    public void start() throws IOException {
   
        // 1. 创建Selector
        Selector selector = Selector.open();

        // 2. 通过ServerSocket创建channel通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        // 3. 为channel通道绑定监听端口
        serverSocketChannel.bind(new InetSocketAddress(8000));

        // 4. 将channel设置为非阻塞模式
        serverSocketChannel.configureBlocking(false);

        // 5. 将channel注册到selector上,监听连接事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务器端启动成功!");

        // 6. 循环等待新接入的连接
        for (; ; ) {
   
            // 获取可用的channel数量
            int readyChannels = selector.select();
            // 屏蔽未就绪的连接,防止selector空轮询
            if (readyChannels == 0) {
   
                continue;
            }
            // 获取可用的channel集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys
  • 11
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值