前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >NIO - 多人聊天室Demo代码

NIO - 多人聊天室Demo代码

作者头像
夹胡碰
发布2021-03-11 11:31:37
1.5K0
发布2021-03-11 11:31:37
举报
文章被收录于专栏:程序猿~

1. 目录结构

1. NioServer
代码语言:javascript
复制
package com.xu.nio;

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

/**
 * @author jiafupeng
 * @desc
 * @create 2021/3/7 19:11
 * @update 2021/3/7 19:11
 **/
public class NioServer {

    /**
     * 启动
     */
    public void start() throws IOException {
        // 1. 创建Selector
        Selector selector = Selector.open();
        // 2. 通过ServerSocketChannel创建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();
            if(readyChannels == 0){continue;}
            // 获取可用channel的集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()){
                // selectionKey实例
                SelectionKey selectionKey = iterator.next();
                // 移除
                iterator.remove();
                // 7. 根据就绪状态,调用对应方法处理业务逻辑
                // 如果是 接入事件
                if(selectionKey.isAcceptable()){
                    acceptHandler(selectionKey, selector);
                }
                // 如果是 可读事件
                if(selectionKey.isReadable()){
                    readHandler(selectionKey, selector);
                }
            }
        }
    }

    /**
     * 接入事件处理器
     */
    private void acceptHandler(SelectionKey selectionKey,
                               Selector selector)
            throws IOException {
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel)selectionKey.channel();
        // 要是接入事件,创建socketChannel
        SocketChannel socketChannel = serverSocketChannel.accept();
        // 将socketChannel设置为非阻塞工作模式
        socketChannel.configureBlocking(false);
        // 将channel注册到selector上,监听可读事件
        socketChannel.register(selector, SelectionKey.OP_READ);
        // 回复客户端提示信息
         socketChannel.write(Charset.forName("UTF-8").encode("<==== 欢迎进入聊天室 ====>"));
    }

    /**
     * 可读事件处理器
     */
    private void readHandler(SelectionKey selectionKey,
                             Selector selector)
            throws IOException {
        // 要从 selectionKey 中获取已经就绪的channel
        SocketChannel socketChannel = (SocketChannel)selectionKey.channel();
        // 创建buffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        // 循环读取客户端请求信息
        String request = "";
        while (socketChannel.read(byteBuffer) > 0){
            // 切换buffer为读模式
            byteBuffer.flip();
            // 读取buffer中的内容
            request += Charset.forName("UTF-8").decode(byteBuffer);
        }
        // 将channel再次注册到selector上,监听其他的可读事件
        socketChannel.register(selector, SelectionKey.OP_READ);
        // 将客户端发送的请求信息 广播给其他客户端
        if(request.length() > 0){
            broadCast(selector, socketChannel, request);
        }
    }

    private void broadCast(Selector selector,
                           SocketChannel sourceChannel, String request){
        Set<SelectionKey> selectionKeySet = selector.keys();
        selectionKeySet.stream().forEach(selectionKey -> {
            Channel targetChannel = selectionKey.channel();

            // 剔除发消息的客户端
            if (targetChannel instanceof SocketChannel
                    && targetChannel != sourceChannel) {
                try {
                    // 将信息发送到targetChannel客户端
                    ((SocketChannel) targetChannel).write(
                            Charset.forName("UTF-8").encode(request));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public static void main(String[] args) throws IOException {
        NioServer nioServer = new NioServer();
        nioServer.start();
    }
}
2. NioClient
代码语言:javascript
复制
package com.xu.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Scanner;

/**
 * @author jiafupeng
 * @desc
 * @create 2021/3/7 19:42
 * @update 2021/3/7 19:42
 **/
public class NioClient {

    private String nickname;

    public NioClient(String nickname) {
        this.nickname = nickname;
    }

    public void start() throws IOException {
        // 连接服务器端
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8000));

        // 接受服务端响应
        Selector selector = Selector.open();
        socketChannel.configureBlocking(false);
        socketChannel.register(selector, SelectionKey.OP_READ);
        new Thread(new NioClientHandler(selector)).start();

        // 向服务器端发送数据
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()){
            String request = scanner.nextLine();
            if(request != null && request.length() > 0){
                socketChannel.write(Charset.forName("UTF-8").encode(nickname + " : " + request));
            }
        }
    }
}
3. NioClientHandler
代码语言:javascript
复制
package com.xu.nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

/**
 * @author jiafupeng
 * @desc
 * @create 2021/3/8 10:14
 * @update 2021/3/8 10:14
 **/
public class NioClientHandler implements Runnable {

    private Selector selector;

    public NioClientHandler(Selector selector) {
        this.selector = selector;
    }

    @Override
    public void run() {
        try {
            for (;;) {
                int readyChannels = selector.select();
                if (readyChannels == 0) {continue;}
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = (SelectionKey) iterator.next();
                    iterator.remove();
                    if (selectionKey.isReadable()) {
                        readHandler(selectionKey, selector);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void readHandler(SelectionKey selectionKey, Selector selector) throws IOException {
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        String response = "";
        while (socketChannel.read(byteBuffer) > 0) {
            // 切换buffer为读模式
            byteBuffer.flip();
            // 读取buffer中的内容
            response += Charset.forName("UTF-8").decode(byteBuffer);
        }
        // 将channel再次注册到selector上,监听他的可读事件
        socketChannel.register(selector, SelectionKey.OP_READ);
        // 将服务器端响应信息打印到本地
        if (response.length() > 0) {
            System.out.println(response);
        }

    }
}
4. XXClient
代码语言:javascript
复制
package com.xu.nio;

import java.io.IOException;

/**
 * @author jiafupeng
 * @desc
 * @create 2021/3/8 10:59
 * @update 2021/3/8 10:59
 **/
public class XXClient {

    public static void main(String[] args) throws IOException {
        new NioClient("jiafupeng").start();
    }
}
5. YYClient
代码语言:javascript
复制
package com.xu.nio;

import java.io.IOException;

/**
 * @author jiafupeng
 * @desc
 * @create 2021/3/8 10:59
 * @update 2021/3/8 10:59
 **/
public class YYClient {

    public static void main(String[] args) throws IOException {
        new NioClient("wangdongxu").start();
    }
}

结果展示

  • 服务器
  • XXClient
  • YYClient
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 目录结构
    • 1. NioServer
      • 2. NioClient
        • 3. NioClientHandler
          • 4. XXClient
            • 5. YYClient
            • 结果展示
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档