JAVA NIO实现简单聊天室功能

本文实例为大家分享了JAVA NIO实现简单聊天室功能的具体代码,供大家参考,具体内容如下

服务端

初始化一个ServerSocketChannel,绑定端口,然后使用Selector监听accept事件。

当有accept发生时,表示有客户端连接进来了,获取客户端的SocketChannel,然后注册其read事件;用来接收客户端发送的消息。

package chatroom;

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.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 服务端
 *
 * @author wenei
 * @date 2021-07-20 20:36
 */
public class Server {

    private static final Logger log = Logger.getLogger(Server.class.getName());

    private int port;

    private List<SocketChannel> clientChannelList = new ArrayList<>();

    public Server(int port) {
        this.port = port;
    }

    public void start() throws IOException {
        // 初始化服务端channel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(port));
        serverSocketChannel.configureBlocking(false);
        // 新建Selector
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
            final int selectCount = selector.select();
            if (selectCount <= 0) {
                continue;
            }
            final Set<SelectionKey> selectionKeys = selector.selectedKeys();
            final Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                final SelectionKey key = iterator.next();
                iterator.remove();
                if (key.isAcceptable()) {
                    // 当有accept事件时,将新的连接加入Selector
                    ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                    SocketChannel accept = serverChannel.accept();
                    accept.configureBlocking(false);
                    clientChannelList.add(accept);
                    accept.register(selector, SelectionKey.OP_READ);
                    log.log(Level.INFO, "新连接 " + accept);
                } else if (key.isReadable()) {
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    log.log(Level.INFO, "可读连接 " + socketChannel);
                    ByteBuffer buffer = ByteBuffer.allocate(60);
                    try {
                        /**
                         * 当客户端非正常退出时,read抛出异常,属于被动性关闭;
                         * 当客户端正常返回时,返回-1,但也是readable信号,所以需要处理
                         */
                        final int read = socketChannel.read(buffer);
                        if (read == -1) {
                            log.log(Level.INFO, "连接主动关闭:" + socketChannel);
                            clientChannelList.remove(socketChannel);
                            socketChannel.close();
                            continue;
                        }
                    } catch (IOException e) {
                        log.log(Level.INFO, "连接被动关闭:" + socketChannel);
                        clientChannelList.remove(socketChannel);
                        socketChannel.close();
                        continue;
                    }
                    buffer.flip();
                    byte[] bytes = new byte[60];
                    int index = 0;
                    while (buffer.hasRemaining()) {
                        bytes[index++] = buffer.get();
                    }
                    bytes[index] = '\0';
                    log.log(Level.INFO, "接受数据: " + new String(bytes, StandardCharsets.UTF_8).trim());
                    // 广播
                    clientChannelList.forEach(channel -> {
                        if (channel != socketChannel) {
                            buffer.flip();
                            try {
                                channel.write(buffer);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    });
//                    buffer.clear();
                }
            }
        }
    }

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

客户端

使用主线程获取键盘输入,然后传给服务端。

使用子线程接收服务端发送的信息并显示。

package chatroom;

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.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

/**
 * 客户端
 *
 * @author wenei
 * @date 2021-07-21 9:14
 */
public class Client {

    /**
     * 客户端接收信息线程
     */
    static class ClientReceiveThread implements Runnable {

        /**
         * 客户端socket
         */
        private SocketChannel socketChannel;

        public ClientReceiveThread(SocketChannel socketChannel) {
            this.socketChannel = socketChannel;
        }

        @Override
        public void run() {
            try {
                Selector selector = Selector.open();
                socketChannel.register(selector, SelectionKey.OP_READ);
                while (true) {
                    final int selectCount = selector.select(100);
                    if (Thread.currentThread().isInterrupted()) {
                        System.out.println("连接关闭");
                        socketChannel.close();
                        return;
                    }
                    if (selectCount <= 0) {
                        continue;
                    }
                    final Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    final Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while (iterator.hasNext()) {
                        final SelectionKey key = iterator.next();
                        iterator.remove();
                        if (key.isReadable()) {
                            ByteBuffer recvBuffer = ByteBuffer.allocate(60);
                            socketChannel.read(recvBuffer);
                            recvBuffer.flip();
                            byte[] bytes = new byte[60];
                            int index = 0;
                            while (recvBuffer.hasRemaining()) {
                                bytes[index++] = recvBuffer.get();
                            }
                            bytes[index] = '\0';
                            System.out.println("接受数据: " + new String(bytes, StandardCharsets.UTF_8).trim());
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private int port;

    public Client(int port) {
        this.port = port;
    }

    public void start() throws IOException {
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(port));
        socketChannel.configureBlocking(false);
        Scanner scanner = new Scanner(System.in);
        ByteBuffer buffer = ByteBuffer.allocate(60);
        Thread thread = new Thread(new ClientReceiveThread(socketChannel));
        thread.start();
        while (true) {
            String data = scanner.nextLine();
            if (data.equals("exit")) {
                break;
            }
            System.out.println("输入数据:" + data);
            buffer.put(data.getBytes(StandardCharsets.UTF_8));
            buffer.flip();
            socketChannel.write(buffer);
            buffer.clear();
        }
        thread.interrupt();
    }

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java NIO实战之聊天室功能详解

    本文实例讲述了Java NIO实战之聊天室功能.分享给大家供大家参考,具体如下: 在工作之余花了两个星期看完了<Java NIO>,总体来说这本书把NIO写的很详细,没有过多的废话,讲的都是重点,只是翻译的中文版看的确实吃力,英文水平太低也没办法,总算也坚持看完了.<Java NIO>这本书的重点在于第四章讲解的"选择器",要理解透还是要反复琢磨推敲:愚钝的我花了大概3天的时间才将NIO的选择器机制理解透并能较熟练的运用,于是便写了这个聊天室程序. 下面直接上代

  • Java NIO Selector用法详解【含多人聊天室实例】

    本文实例讲述了Java NIO Selector用法.分享给大家供大家参考,具体如下: 一.Java NIO 的核心组件 Java NIO的核心组件包括:Channel(通道),Buffer(缓冲区),Selector(选择器),其中Channel和Buffer比较好理解 简单来说 NIO是面向通道和缓冲区的,意思就是:数据总是从通道中读到buffer缓冲区内,或者从buffer写入到通道中. 关于Channel 和 Buffer的详细讲解请看:Java NIO 教程 二.Java NIO Se

  • Java NIO实现聊天室功能

    本文实例为大家分享了Java NIO实现聊天室功能的具体代码,供大家参考,具体内容如下 代码里面已经包含了必要的注释,这里不详述了.实现了基本的聊天室功能. 常量类: public class Constant { public static final int serverPort = 44444; } 服务端: package server; import java.io.IOException; import java.net.InetSocketAddress; import java.

  • Java NIO实现多人聊天室

    本文实例为大家分享了Java NIO实现多人聊天室的具体代码,供大家参考,具体内容如下 1. 服务器端代码 ChatServer类: package nio.test.server; import java.io.Closeable; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; import java.n

  • 使用Java和WebSocket实现网页聊天室实例代码

    在没介绍正文之前,先给大家介绍下websocket的背景和原理: 背景 在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 flex ajax bridge,可以在javascript中使用这两项功能. 可以预见,如果websocket一旦在浏览器中得到实现,将会替代上面两项技术,得到广泛的使用.面对这种状况,HTML5定义了WebSocket协议,能更

  • java基于netty NIO的简单聊天室的实现

    一.为何要使用netty开发 由于之前已经用Java中的socket写过一版简单的聊天室,这里就不再对聊天室的具体架构进行细致的介绍了,主要关注于使用netty框架重构后带来的改变.对聊天室不了解的同学可以先看下我的博客(<JAVA简单聊天室的实现>) 本篇博客所使用的netty版本为4.1.36,完整工程已上传到Github(https://github.com/Alexlingl/Chatroom),其中lib文件夹下有相应的netty jar包和source包,自行导入即可. 1.为何要

  • java聊天室的实现代码

    本文实例为大家分享了java实现聊天室的具体代码,供大家参考,具体内容如下 聊天室界面: 源码: public class ClientFrame extends Frame { private TextField textFieldContent = new TextField(); private TextArea textAreaContent = new TextArea(); private Socket socket = null; private OutputStream out

  • Java实现NIO聊天室的示例代码(群聊+私聊)

    功能介绍 功能:群聊+私发+上线提醒+下线提醒+查询在线用户 文件 Utils 需要用maven导入下面两个包 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> </dependency> <dependency> <group

  • Java基于socket实现简易聊天室实例

    本文实例讲述了Java基于socket实现简易聊天室的方法.分享给大家供大家参考.具体实现方法如下: chatroomdemo.java package com.socket.demo; import java.io.IOException; import java.net.DatagramSocket; public class ChatRoomDemo { /** * @param args * @throws IOException */ public static void main(S

  • Java基于NIO实现聊天室功能

    本文实例为大家分享了Java基于NIO实现聊天室功能的具体代码,供大家参考,具体内容如下 Sever端 package com.qst.one; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.Channel; import java.nio.channels.SelectableChannel; impor

随机推荐