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

JAVA NIO實(shí)現(xiàn)簡單聊天室功能

 更新時(shí)間:2021年11月24日 10:37:38   作者:肥?;疱? 
這篇文章主要為大家詳細(xì)介紹了JAVA NIO實(shí)現(xiàn)簡單聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了JAVA NIO實(shí)現(xiàn)簡單聊天室功能的具體代碼,供大家參考,具體內(nèi)容如下

服務(wù)端

初始化一個(gè)ServerSocketChannel,綁定端口,然后使用Selector監(jiān)聽accept事件。

當(dāng)有accept發(fā)生時(shí),表示有客戶端連接進(jìn)來了,獲取客戶端的SocketChannel,然后注冊(cè)其read事件;用來接收客戶端發(fā)送的消息。

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;

/**
 * 服務(wù)端
 *
 * @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 {
        // 初始化服務(wù)端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()) {
                    // 當(dāng)有accept事件時(shí),將新的連接加入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 {
                        /**
                         * 當(dāng)客戶端非正常退出時(shí),read拋出異常,屬于被動(dòng)性關(guān)閉;
                         * 當(dāng)客戶端正常返回時(shí),返回-1,但也是readable信號(hào),所以需要處理
                         */
                        final int read = socketChannel.read(buffer);
                        if (read == -1) {
                            log.log(Level.INFO, "連接主動(dòng)關(guān)閉:" + socketChannel);
                            clientChannelList.remove(socketChannel);
                            socketChannel.close();
                            continue;
                        }
                    } catch (IOException e) {
                        log.log(Level.INFO, "連接被動(dòng)關(guān)閉:" + 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, "接受數(shù)據(jù): " + 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();
    }
}

客戶端

使用主線程獲取鍵盤輸入,然后傳給服務(wù)端。

使用子線程接收服務(wù)端發(fā)送的信息并顯示。

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("連接關(guān)閉");
                        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("接受數(shù)據(jù): " + 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("輸入數(shù)據(jù):" + 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();
    }
}

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java設(shè)計(jì)模式之觀察者模式解析

    Java設(shè)計(jì)模式之觀察者模式解析

    這篇文章主要介紹了Java設(shè)計(jì)模式之觀察者模式解析,觀察者模式,又被稱為發(fā)布/訂閱模式,它定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象,這個(gè)主題對(duì)象在狀態(tài)變化時(shí),會(huì)通知所有的觀察者對(duì)象,使他們能夠自動(dòng)更新自己,需要的朋友可以參考下
    2023-09-09
  • SpringBoot 整合jdbc和mybatis的方法

    SpringBoot 整合jdbc和mybatis的方法

    該文章主要為記錄如何在SpringBoot項(xiàng)目中整合JDBC和MyBatis,在整合中我會(huì)使用簡單的用法和測試用例,感興趣的朋友跟隨小編一起看看吧
    2019-11-11
  • SpringBoot 在測試時(shí)如何指定包的掃描范圍

    SpringBoot 在測試時(shí)如何指定包的掃描范圍

    這篇文章主要介紹了SpringBoot 在測試時(shí)如何指定包的掃描范圍,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • SpringBoot加載應(yīng)用事件監(jiān)聽器代碼實(shí)例

    SpringBoot加載應(yīng)用事件監(jiān)聽器代碼實(shí)例

    這篇文章主要介紹了SpringBoot加載應(yīng)用事件監(jiān)聽器代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • JVM中堆內(nèi)存和棧內(nèi)存的區(qū)別

    JVM中堆內(nèi)存和棧內(nèi)存的區(qū)別

    本文主要介紹了JVM中堆內(nèi)存和棧內(nèi)存的區(qū)別,具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-02-02
  • Java中調(diào)用SQL Server存儲(chǔ)過程詳解

    Java中調(diào)用SQL Server存儲(chǔ)過程詳解

    這篇文章主要介紹了Java中調(diào)用SQL Server存儲(chǔ)過程詳解,本文講解了使用不帶參數(shù)的存儲(chǔ)過程、使用帶有輸入?yún)?shù)的存儲(chǔ)過程、使用帶有輸出參數(shù)的存儲(chǔ)過程、使用帶有返回狀態(tài)的存儲(chǔ)過程、使用帶有更新計(jì)數(shù)的存儲(chǔ)過程等操作實(shí)例,需要的朋友可以參考下
    2015-01-01
  • k8s+springboot+CronJob定時(shí)任務(wù)部署實(shí)現(xiàn)

    k8s+springboot+CronJob定時(shí)任務(wù)部署實(shí)現(xiàn)

    本文主要介紹了k8s+springboot+CronJob定時(shí)任務(wù)部署實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Java8 CompletableFuture詳解

    Java8 CompletableFuture詳解

    這篇文章主要介紹了Java8 CompletableFuture詳解,CompletableFuture extends Future提供了方法,一元操作符和促進(jìn)異步性以及事件驅(qū)動(dòng)編程模型,需要的朋友可以參考下
    2014-06-06
  • Java?離線中文語音文字識(shí)別功能的實(shí)現(xiàn)代碼

    Java?離線中文語音文字識(shí)別功能的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Java?離線中文語音文字識(shí)別,本次使用springboot?+maven實(shí)現(xiàn),官方demo為springboot+gradle,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • java啟動(dòng)jar包修改JVM默認(rèn)內(nèi)存問題

    java啟動(dòng)jar包修改JVM默認(rèn)內(nèi)存問題

    這篇文章主要介紹了java啟動(dòng)jar包修改JVM默認(rèn)內(nèi)存問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02

最新評(píng)論

凤翔县| 金湖县| 杭锦后旗| 夏津县| 西和县| 敖汉旗| 石台县| 遂川县| 大姚县| 南通市| 通化市| 吉安县| 吉首市| 探索| 元氏县| 迁安市| 金昌市| 鹤山市| 恩施市| 启东市| 离岛区| 共和县| 塔城市| 稻城县| 铜陵市| 区。| 大兴区| 米易县| 如皋市| 仲巴县| 正蓝旗| 堆龙德庆县| 竹溪县| 神农架林区| 天峨县| 砀山县| 景谷| 廊坊市| 晋江市| 渝中区| 青河县|