最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實現(xiàn)NIO聊天室的示例代碼(群聊+私聊)

 更新時間:2021年05月11日 14:13:19   作者:馬走日mazouri  
這篇文章主要介紹了Java實現(xiàn)NIO聊天室的示例代碼(群聊+私聊),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

功能介紹

功能:群聊+私發(fā)+上線提醒+下線提醒+查詢在線用戶

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

文件

Utils

需要用maven導(dǎo)入下面兩個包

 <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.18</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
package moremorechat_nio;

import lombok.extern.slf4j.Slf4j;

import java.io.*;

/**
 * @author mazouri
 * @create 2021-05-09 22:26
 */
@Slf4j
public class Utils {
    /**
     * 將二進制數(shù)據(jù)轉(zhuǎn)為對象
     *
     * @param buf
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static Message decode(byte[] buf) throws IOException, ClassNotFoundException {
        ByteArrayInputStream bais = new ByteArrayInputStream(buf);
        ObjectInputStream ois = new ObjectInputStream(bais);
        return (Message) ois.readObject();
    }

    /**
     * 將對象轉(zhuǎn)為二進制數(shù)據(jù)
     *
     * @param message
     * @return
     */
    public static byte[] encode(Message message) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(message);
        oos.flush();
        return baos.toByteArray();
    }
}

FinalValue

package moremorechat_nio;
/**
 * @author mazouri
 * @create 2021-05-05 21:00
 */
public final class FinalValue {
    /**
     * 系統(tǒng)消息
     */
    public static final int MSG_SYSTEM = 0;
    /**
     * 群發(fā)消息
     */
    public static final int MSG_GROUP = 1;
    /**
     * 私發(fā)消息
     */
    public static final int MSG_PRIVATE = 2;
    /**
     * 客戶端請求在線人員
     */
    public static final int MSG_ONLINE = 3;
    /**
     * 客戶端將用戶名稱發(fā)送給服務(wù)端
     */
    public static final int MSG_NAME = 4;
}

Message

package moremorechat_nio;

import java.io.Serializable;

/**
 * @author mazouri
 * @create 2021-05-05 21:00
 */
public class Message implements Serializable {
    public int type;
    public String message;

    public Message() {
    }

    public Message(String message) {
        this.message = message;
    }

    public Message(int type, String message) {
        this.type = type;
        this.message = message;
    }

    @Override
    public String toString() {
        return "Message{" +
                "type=" + type +
                ", message='" + message + '\'' +
                '}';
    }
}

NioServer

package moremorechat_nio;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import static moremorechat_nio.FinalValue.*;

/**
 * ctrl+f12 方法
 * ctrl+alt+左鍵
 * @author mazouri
 * @create 2021-05-09 19:24
 */
@Slf4j
public class NioServer {
    private Selector selector;
    private ServerSocketChannel ssc;

    public NioServer() {
        try {
            // 創(chuàng)建 selector, 管理多個 channel
            selector = Selector.open();
            //打開ServerSocketChannel,用于監(jiān)聽客戶端的連接,它是所有客戶端連接的父通道
            ssc = ServerSocketChannel.open();
            ssc.bind(new InetSocketAddress(8888));
            //設(shè)置連接為非堵塞模式
            ssc.configureBlocking(false);
            // 2. 建立 selector 和 channel 的聯(lián)系(注冊)
            // SelectionKey 就是將來事件發(fā)生后,通過它可以知道事件和哪個channel的事件
            //將ServerSocketChannel注冊到Reactor線程的多路復(fù)用器Selector上,監(jiān)聽ACCEPT事件
            ssc.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        NioServer server = new NioServer();
        log.debug("server啟動完成,等待用戶連接...");
        try {
            server.listen();
        } catch (Exception e) {
            log.debug("發(fā)生了一些問題");
        }
    }

    /**
     * 監(jiān)聽用戶的連接
     *
     * @throws Exception
     */
    private void listen() throws Exception {
        while (true) {
            // select 方法, 沒有事件發(fā)生,線程阻塞,有事件,線程才會恢復(fù)運行, 通過Selector的select()方法可以選擇已經(jīng)準備就緒的通道 (這些通道包含你感興趣的的事件)
            //通過Selector的select()方法可以選擇已經(jīng)準備就緒的通道 (這些通道包含你感興趣的的事件)
            // select 在事件未處理時,它不會阻塞, 事件發(fā)生后要么處理,要么取消,不能置之不理
            selector.select();
            // 處理事件, selectedKeys 內(nèi)部包含了所有發(fā)生的事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                // 處理key 時,要從 selectedKeys 集合中刪除,否則下次處理就會有問題
                iterator.remove();
                // 區(qū)分事件類型
                if (key.isAcceptable()) {
                    ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                    SocketChannel sc = channel.accept();
                    sc.configureBlocking(false);
                    sc.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    dealReadEvent(key);
                }
            }
        }
    }

    /**
     * 處理讀事件
     *
     * @param key
     */
    private void dealReadEvent(SelectionKey key) {
        SocketChannel channel = null;
        try {
            channel = (SocketChannel) key.channel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int read = channel.read(buffer);
            // 如果是正常斷開,read 的方法的返回值是 -1
            if (read == -1) {
                //cancel 會取消注冊在 selector 上的 channel,并從 keys 集合中刪除 key 后續(xù)不會再監(jiān)聽事件
                key.cancel();
            } else {
                buffer.flip();
                Message msg = Utils.decode(buffer.array());
                log.debug(msg.toString());
                dealMessage(msg, key, channel);
            }
        } catch (IOException | ClassNotFoundException e) {
            System.out.println((key.attachment() == null ? "匿名用戶" : key.attachment()) + " 離線了..");
            dealMessage(new Message(MSG_SYSTEM, key.attachment() + " 離線了.."), key, channel);
            //取消注冊
            key.cancel();
            //關(guān)閉通道
            try {
                channel.close();
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }
    }

    /**
     * 處理各種消息,并發(fā)送給客戶端
     *
     * @param msg
     * @param key
     * @param channel
     */
    private void dealMessage(Message msg, SelectionKey key, SocketChannel channel) {
        switch (msg.type) {
            case MSG_NAME:
                key.attach(msg.message);
                log.debug("用戶{}已上線", msg.message);
                getConnectedChannel(channel).forEach(selectionKey -> {
                    SocketChannel sc = (SocketChannel) selectionKey.channel();
                    sendMsgToClient(new Message("收到一條系統(tǒng)消息: " + msg.message + "已上線"), sc);
                });
                break;
            case MSG_GROUP:
                getConnectedChannel(channel).forEach(selectionKey -> {
                    SocketChannel sc = (SocketChannel) selectionKey.channel();
                    sendMsgToClient(new Message(key.attachment() + "給大家發(fā)送了一條消息: " + msg.message), sc);
                });
                break;
            case MSG_PRIVATE:
                String[] s = msg.message.split("_");
                AtomicBoolean flag = new AtomicBoolean(false);
                getConnectedChannel(channel).stream().filter(sk -> s[0].equals(sk.attachment())).forEach(selectionKey -> {
                    SocketChannel sc = (SocketChannel) selectionKey.channel();
                    sendMsgToClient(new Message(key.attachment() + "給你發(fā)送了一條消息: " + s[1]), sc);
                    flag.set(true);
                });
                if (!flag.get()){
                    sendMsgToClient(new Message(s[1]+"用戶不存在,請重新輸入?。?!"), channel);
                }

                break;
            case MSG_ONLINE:
                ArrayList<String> onlineList = new ArrayList<>();
                onlineList.add((String) key.attachment());
                getConnectedChannel(channel).forEach(selectionKey -> onlineList.add((String) selectionKey.attachment()));
                sendMsgToClient(new Message(onlineList.toString()), channel);
                break;
            case MSG_SYSTEM:
                getConnectedChannel(channel).forEach(selectionKey -> {
                    SocketChannel sc = (SocketChannel) selectionKey.channel();
                    sendMsgToClient(new Message("收到一條系統(tǒng)消息: " + msg.message), sc);
                });
                break;
            default:
                break;
        }
    }

    /**
     * 發(fā)送消息給客戶端
     *
     * @param msg
     * @param sc
     */
    private void sendMsgToClient(Message msg, SocketChannel sc) {
        try {
            byte[] bytes = Utils.encode(msg);
            sc.write(ByteBuffer.wrap(bytes));
        } catch (IOException e) {
            log.debug("sendMsgToClient出現(xiàn)了一些問題");
        }
    }

    /**
     * 獲取所有channel,除去調(diào)用者
     *
     * @param channel
     * @return
     */
    private Set<SelectionKey> getConnectedChannel(SocketChannel channel) {
        return selector.keys().stream()
                .filter(item -> item.channel() instanceof SocketChannel && item.channel().isOpen() && item.channel() != channel)
                .collect(Collectors.toSet());
    }
}

NioClient

package moremorechat_nio;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
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.util.Iterator;
import java.util.Scanner;

import static moremorechat_nio.FinalValue.*;

/**
 * @author mazouri
 * @create 2021-04-29 12:02
 */
@Slf4j
public class NioClient {
    private Selector selector;
    private SocketChannel socketChannel;
    private String username;
    private static Scanner input;

    public NioClient() throws IOException {
        selector = Selector.open();
        socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8888));
        socketChannel.configureBlocking(false);
        socketChannel.register(selector, SelectionKey.OP_READ);
        log.debug("client啟動完成......");
        log.debug("請輸入你的名字完成注冊");
        input = new Scanner(System.in);
        username = input.next();
        log.debug("歡迎{}來到聊天系統(tǒng)", username);
    }

    public static void main(String[] args) throws IOException {
        System.out.println("tips: \n1. 直接發(fā)送消息會發(fā)給當(dāng)前的所有用戶 \n2. @用戶名:消息  會私發(fā)給你要發(fā)送的用戶 \n3. 輸入  查詢在線用戶  會顯示當(dāng)前的在線用戶");
        NioClient client = new NioClient();

        //啟動一個子線程接受服務(wù)器發(fā)送過來的消息
        new Thread(() -> {
            try {
                client.acceptMessageFromServer();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "receiveClientThread").start();

        //調(diào)用sendMessageToServer,發(fā)送消息到服務(wù)端
        client.sendMessageToServer();
    }

    /**
     * 將消息發(fā)送到服務(wù)端
     *
     * @throws IOException
     */
    private void sendMessageToServer() throws IOException {
        //先把用戶名發(fā)給客戶端
        Message message = new Message(MSG_NAME, username);
        byte[] bytes = Utils.encode(message);

        socketChannel.write(ByteBuffer.wrap(bytes));
        while (input.hasNextLine()) {
            String msgStr = input.next();

            Message msg;
            boolean isPrivate = msgStr.startsWith("@");
            if (isPrivate) {
                int idx = msgStr.indexOf(":");
                String targetName = msgStr.substring(1, idx);
                msgStr = msgStr.substring(idx + 1);
                msg = new Message(MSG_PRIVATE, targetName + "_" + msgStr);
            } else if ("查詢在線用戶".equals(msgStr)) {
                msg = new Message(MSG_ONLINE, "請求在線人數(shù)");
            } else {
                msg = new Message(MSG_GROUP, msgStr);
            }

            byte[] bytes1 = Utils.encode(msg);
            socketChannel.write(ByteBuffer.wrap(bytes1));
        }
    }

    /**
     * 接受從服務(wù)器發(fā)送過來的消息
     */
    private void acceptMessageFromServer() throws Exception {
        while (selector.select() > 0) {
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();
                if (key.isReadable()) {
                    SocketChannel sc = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    sc.read(buffer);
                    Message message = Utils.decode(buffer.array());
                    log.debug(String.valueOf(message.message));
                }
            }
        }
    }
}

到此這篇關(guān)于Java實現(xiàn)NIO聊天室的示例代碼(群聊+私聊)的文章就介紹到這了,更多相關(guān)Java NIO聊天室內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java使用connectTo方法提高代碼可續(xù)性詳解

    Java使用connectTo方法提高代碼可續(xù)性詳解

    這篇文章主要介紹了Java使用connectTo方法提高代碼可續(xù)性,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Java正則表達式判斷是否包含數(shù)字、字母、特殊字符及中文的多種方法

    Java正則表達式判斷是否包含數(shù)字、字母、特殊字符及中文的多種方法

    這篇文章主要給大家介紹了關(guān)于Java正則表達式判斷是否包含數(shù)字、字母、特殊字符及中文的多種方法,Java正則表達式在字符串處理和模式匹配中扮演著重要角色,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-08-08
  • springboot實現(xiàn)多文件上傳功能

    springboot實現(xiàn)多文件上傳功能

    這篇文章主要為大家詳細介紹了springboot實現(xiàn)多文件上傳功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • 解決IDEA maven 項目修改代碼不生效,mvn clean、install后才生效

    解決IDEA maven 項目修改代碼不生效,mvn clean、install后才生效

    這篇文章主要介紹了解決IDEA maven 項目修改代碼不生效,mvn clean、install后才生效的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 【MyBatis源碼全面解析】MyBatis一二級緩存介紹

    【MyBatis源碼全面解析】MyBatis一二級緩存介紹

    下面小編就為大家?guī)硪黄綧yBatis源碼全面解析】MyBatis一二級緩存介紹。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • 淺談SpringBoot2.3 新特配置文件屬性跟蹤

    淺談SpringBoot2.3 新特配置文件屬性跟蹤

    這篇文章主要介紹了淺談SpringBoot2.3 新特配置文件屬性跟蹤,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • 深入理解與應(yīng)用Java抽象類

    深入理解與應(yīng)用Java抽象類

    Java抽象類是一個非常重要的概念,它允許我們定義包含抽象方法和非抽象方法的類,并為子類提供通用的屬性和方法,本文給大家介紹Java抽象類的理解與應(yīng)用,感興趣的朋友一起看看吧
    2025-04-04
  • SpringBoot實現(xiàn)WebSocket即時通訊的示例代碼

    SpringBoot實現(xiàn)WebSocket即時通訊的示例代碼

    本文主要介紹了SpringBoot實現(xiàn)WebSocket即時通訊的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Spring中的Lifecycle接口使用與源碼分析

    Spring中的Lifecycle接口使用與源碼分析

    這篇文章主要介紹了Spring中的Lifecycle接口使用與源碼分析,LifeCycle接口定義了Spring容器的生命周期,任何被Spring管理的對象都可以實現(xiàn)該接口,需要的朋友可以參考下
    2023-05-05
  • 搭建MyBatis開發(fā)環(huán)境及基本的CURD介紹

    搭建MyBatis開發(fā)環(huán)境及基本的CURD介紹

    這篇文章主要介紹了搭建MyBatis開發(fā)環(huán)境及基本的CURD,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08

最新評論

开化县| 仪征市| 高邮市| 广饶县| 丰都县| 吉木萨尔县| 东阳市| 甘肃省| 加查县| 淮南市| 会昌县| 连山| 岑巩县| 镇安县| 留坝县| 鹤峰县| 南投市| 平山县| 南涧| 伽师县| 塔城市| 乌鲁木齐县| 彭水| 恩施市| 娱乐| 尼勒克县| 浮山县| 保山市| 合川市| 乐亭县| 承德市| 平泉县| 十堰市| 射阳县| 贵定县| 天镇县| 榕江县| 梨树县| 科技| 时尚| 根河市|