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

Java BIO實(shí)現(xiàn)聊天程序

 更新時(shí)間:2021年11月24日 10:16:45   作者:java碩哥  
這篇文章主要為大家詳細(xì)介紹了Java BIO實(shí)現(xiàn)聊天程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了Java BIO實(shí)現(xiàn)聊天程序的具體代碼,供大家參考,具體內(nèi)容如下

我們使用一個(gè)聊天程序來(lái)說(shuō)本文的主題

1、BIO 客戶端服務(wù)器通訊

public class ChatServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9000);
        while (true) {
            try {
                System.out.println("聊天服務(wù)已啟動(dòng),等待客戶連接....");
                Socket socket = serverSocket.accept();
                System.out.printf("建立了與%s的連接!\n",socket.getRemoteSocketAddress());
                loopReadRequest(socket);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static String loopReadRequest(Socket socket) throws IOException {
        InputStreamReader reader = new InputStreamReader(socket.getInputStream());
        StringBuilder sb = new StringBuilder();
        char[] cbuf = new char[256];
        
        // 循環(huán)讀取socket的輸入數(shù)據(jù)流
        while (true) {
            // read方法,讀出內(nèi)容寫入 char 數(shù)組,read 方法會(huì)一直阻塞
            // 直到有輸入內(nèi)容 或 發(fā)生I/O錯(cuò)誤 或 輸入流結(jié)束(對(duì)方關(guān)閉了socket)
            // 正常讀取時(shí)方法會(huì)返回讀取的字符數(shù),當(dāng)輸入流結(jié)束時(shí)(對(duì)方關(guān)閉了socket)方法返回 -1
            int readed = reader.read(cbuf);
   SocketAddress remoteSocketAddress = socket.getRemoteSocketAddress();
   // 客戶端執(zhí)行了socket.close()
            if (readed == -1) {
                System.out.println(remoteSocketAddress + " 斷開了連接!");
                reader.close();
                socket.close();
                break;
            }

            String readedStr = new String(cbuf, 0, readed);
            sb.append(readedStr);

      // ready()用來(lái)判斷流是否可被讀取,如果reader緩沖區(qū)不是空則返回true,否則返回false
            if (!reader.ready()) {//reader緩沖區(qū)為空,表示數(shù)據(jù)流已讀完
                // 數(shù)據(jù)流已讀完,此時(shí)向客戶端發(fā)送響應(yīng)
                socket.getOutputStream().write((remoteSocketAddress+"你好,"+sb+"已收到").getBytes());
                System.out.println("收到內(nèi)容:"+sb);
                // 清除sb的內(nèi)容,準(zhǔn)備接收下一個(gè)請(qǐng)求內(nèi)容
                sb.setLength(0);
                System.out.println("等待客戶端消息....");
            }
        }
        return sb.toString();
    }
}

public class ChatClient {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("localhost", 9000);
            Scanner scanner = new Scanner(System.in);
            while (true) {
                System.out.print(">");
                String line = scanner.nextLine();
                if("".equals(line)){
                    continue;
                }
                if ("quit".equals(line)) {
                    scanner.close();
                    socket.close();
                    break;
                }
                socket.getOutputStream().write(line.getBytes());
                System.out.println(readRequest(socket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String readRequest(Socket socket) throws IOException {
        InputStreamReader reader = new InputStreamReader(socket.getInputStream());
        StringBuilder sb = new StringBuilder();
        char[] cbuf = new char[256];
        while (true) {
            int readed = reader.read(cbuf);
            // 讀出內(nèi)容寫入 char 數(shù)組,read 方法會(huì)一直阻塞
            // 直到有輸入內(nèi)容 或 發(fā)生I/O錯(cuò)誤 或 輸入流結(jié)束(對(duì)方關(guān)閉了socket)
            // 正常讀取,方法會(huì)返回讀取的字符數(shù),而當(dāng)輸入流結(jié)束(對(duì)方關(guān)閉了socket)則返回 -1
            if (readed == -1) {
                System.out.println(socket.getRemoteSocketAddress() + " 斷開了連接!");
                reader.close();
                socket.close();
                break;
            }

            String readedStr = new String(cbuf, 0, readed);
            sb.append(readedStr);
            if(!reader.ready()){
                break;
            }
        }
        return sb.toString();
    }
}

ChatServer與ChatClient建立了長(zhǎng)連接,且ChatServer阻塞等待ChatClient發(fā)送消息過(guò)來(lái),程序中 Server端只能與一個(gè)Client建立連接。程序這么寫,只能實(shí)現(xiàn)一個(gè)客戶端和服務(wù)端進(jìn)行通信。

如何支持多個(gè)Client的連接呢? 使用獨(dú)立的線程去讀取socket

2、多線程實(shí)現(xiàn)單聊,群聊

單聊發(fā)送 格式:-c 對(duì)方端口號(hào) 消息內(nèi)容, 群聊直接發(fā)送信息就可以了,具體發(fā)送邏輯看下面的程序

public class ChatServer {
    private static Map<String, Socket> connnectedSockets = new ConcurrentHashMap<>();

    public static void main(String[] args) throws IOException {

        // 1、服務(wù)端初始化工作
        ServerSocket serverSocket = new ServerSocket(9000);
        ExecutorService executorService = getExecutorService();

        // 2、主線程- 循環(huán)阻塞接收新的連接請(qǐng)求
        while (true) {
            Socket socket = serverSocket.accept();
            cacheSocket(socket);

            // 3、一個(gè)socket對(duì)應(yīng)一個(gè)讀取任務(wù),交給線程池中的線程執(zhí)行
            // 如果使用fixed線程池,會(huì)操作讀取任務(wù)分配不到線程的情況
            // 現(xiàn)象就是發(fā)送的消息別人收不到(暫存在Socket緩存中)
            executorService.submit(createLoopReadTask(socket));
        }
    }

    private static Runnable createLoopReadTask(Socket socket) {
        return new Runnable() {
            public void run() {
                try {
                    loopReadRequestAndRedirect(socket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
    }

    private static ExecutorService getExecutorService() {
        ExecutorService executorService = Executors.newCachedThreadPool();
        int nThreads = Runtime.getRuntime().availableProcessors();
        nThreads = 1;
        // 如果只設(shè)置一個(gè)線程,那么最先連接進(jìn)來(lái)的客戶端可以發(fā)送消息
        // 因?yàn)槌绦蜃枞x取第一個(gè)socket連接的數(shù)據(jù)流,沒有其他線程資源去讀后面建立的socket了
        executorService = Executors.newFixedThreadPool(nThreads);
        return executorService;
    }

    private static void cacheSocket(Socket socket) {
        SocketAddress remoteSocketAddress = socket.getRemoteSocketAddress();
        String[] split = remoteSocketAddress.toString().split(":");
        connnectedSockets.put(split[1], socket);
    }

    public static String loopReadRequestAndRedirect(Socket socket) throws IOException {
        InputStreamReader reader = new InputStreamReader(socket.getInputStream());
        StringBuilder sb = new StringBuilder();
        char[] cbuf = new char[256];
        while (true) {
            SocketAddress remoteSocketAddress = socket.getRemoteSocketAddress();
            System.out.println(Thread.currentThread() + "執(zhí)行 " + remoteSocketAddress + "發(fā)送的消息");
            // 讀出內(nèi)容寫入 char 數(shù)組,read 方法會(huì)一直阻塞
            // 直到有輸入內(nèi)容 或 發(fā)生I/O錯(cuò)誤 或 輸入流結(jié)束(對(duì)方關(guān)閉了socket)
            // 正常讀取時(shí)方法會(huì)返回讀取的字符數(shù),當(dāng)輸入流結(jié)束(對(duì)方關(guān)閉了socket)時(shí)返回 -1
            int readed = reader.read(cbuf);

            if (readed == -1) {
                System.out.println(remoteSocketAddress + " 斷開了連接!");
                reader.close();
                socket.close();
                break;
            }

            String readedStr = new String(cbuf, 0, readed);
            sb.append(readedStr);

            //ready()用來(lái)判斷流是否可被讀取,如果reader緩沖區(qū)不是空則返回true,否則返回false
            boolean oneReqeustStreamReaded = !reader.ready();
            if (oneReqeustStreamReaded) {
                String requestContent = sb.toString().trim();
                String prifix = requestContent.substring(0, 2);
                // 單聊
                if ("-c".equals(prifix)) {
                    requestContent = requestContent.substring(3);
                    String port = requestContent.substring(0, requestContent.indexOf(" "));
                    requestContent = requestContent.replaceFirst(port, "");
                    sendToOneSocket(connnectedSockets.get(port), requestContent);
                    // 群聊
                } else {
                    // 向客戶端發(fā)送響應(yīng)
                    socket.getOutputStream().write(("您發(fā)送的消息-'" + sb + "' 已收到").getBytes());
                    sendToAllSocket(sb.toString(), socket);
                }
                sb.setLength(0);
            }
        }
        return sb.toString();
    }

    /**
     * 發(fā)送消息給某個(gè)socket
     *
     * @param socket
     * @param msg
     */
    private static void sendToOneSocket(Socket socket, String msg) {
        // 對(duì)于同一個(gè)socket,同一時(shí)刻只有一個(gè)線程使用它發(fā)送消息
        synchronized (socket) {
            try {
                socket.getOutputStream().write(msg.getBytes("UTF-8"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 發(fā)送消息給所有的socket
     *
     * @param msg
     */
    private static void sendToAllSocket(String msg, Socket selfSocket) {
        for (String key : connnectedSockets.keySet()) {
            Socket socket = connnectedSockets.get(key);
            if (socket.equals(selfSocket)) {
                continue;
            }
            sendToOneSocket(socket, msg);
        }
    }
}


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

    public void start() throws IOException {
        Socket socket = new Socket("localhost", 9000);
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        
        Runnable readTask = new Runnable() {
            public void run() {
                try {
                    loopReadRequest(socket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
        executorService.submit(readTask);

        Runnable sendMsgTask = new Runnable() {
            public void run() {
                try {
                    Scanner scanner = new Scanner(System.in);
                    while (true) {
                        System.out.print(">");
                        String line = scanner.nextLine();
                        if ("".equals(line)) {
                            continue;
                        }
                        if ("quit".equals(line)) {
                            scanner.close();
                            socket.close();
                            break;
                        }
                        socket.getOutputStream().write(line.getBytes());
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
        executorService.submit(sendMsgTask);

    }

    public void loopReadRequest(Socket socket) throws IOException {
        InputStreamReader reader = new InputStreamReader(socket.getInputStream());
        StringBuilder sb = new StringBuilder();
        char[] cbuf = new char[256];
        while (true) {
            int readed = reader.read(cbuf);
            // 讀出內(nèi)容寫入 char 數(shù)組,read 方法會(huì)一直阻塞
            // 直到有輸入內(nèi)容 或 發(fā)生I/O錯(cuò)誤 或 輸入流結(jié)束(對(duì)方關(guān)閉了socket)
            // 正常讀取,方法會(huì)返回讀取的字符數(shù),而當(dāng)輸入流結(jié)束(對(duì)方關(guān)閉了socket)則返回 -1
            if (readed == -1) {
                System.out.println(socket.getRemoteSocketAddress() + " 斷開了連接!");
                reader.close();
                socket.close();
                break;
            }

            String readedStr = new String(cbuf, 0, readed);
            sb.append(readedStr);
            if (!reader.ready()) {
                System.out.println(sb);
                sb.setLength(0);
            }
        }
    }
}

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

相關(guān)文章

  • Java實(shí)現(xiàn)樹形結(jié)構(gòu)的示例代碼

    Java實(shí)現(xiàn)樹形結(jié)構(gòu)的示例代碼

    由于業(yè)務(wù)需要,后端需要返回一個(gè)樹型結(jié)構(gòu)給前端,包含父子節(jié)點(diǎn)的數(shù)據(jù)已經(jīng)在數(shù)據(jù)庫(kù)中存儲(chǔ)好。本文將為大家分享Java現(xiàn)樹形結(jié)構(gòu)的示例代碼,需要的可以參考下
    2022-05-05
  • Netty分布式高性能工具類同線程下回收對(duì)象解析

    Netty分布式高性能工具類同線程下回收對(duì)象解析

    這篇文章主要為大家介紹了Netty分布式高性能工具類同線程下回收對(duì)象解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • Spring如何處理注解的深入理解

    Spring如何處理注解的深入理解

    這篇文章主要給大家介紹了關(guān)于Spring如何處理注解的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java中的注解具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • Java連接FTP服務(wù)器并使用ftp連接池進(jìn)行文件操作指南

    Java連接FTP服務(wù)器并使用ftp連接池進(jìn)行文件操作指南

    使用FTP最主要的功能是對(duì)文件進(jìn)行管理,下面這篇文章主要給大家介紹了關(guān)于Java連接FTP服務(wù)器并使用ftp連接池進(jìn)行文件操作的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-08-08
  • springboot整合redis之消息隊(duì)列

    springboot整合redis之消息隊(duì)列

    本文主要介紹了springboot整合redis之消息隊(duì)列,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • java:程序包org.apache.ibatis.annotations不存在報(bào)錯(cuò)解決

    java:程序包org.apache.ibatis.annotations不存在報(bào)錯(cuò)解決

    這篇文章主要給大家介紹了關(guān)于java:程序包org.apache.ibatis.annotations不存在報(bào)錯(cuò)的解決方法,這個(gè)錯(cuò)誤是我在直接導(dǎo)入springboot項(xiàng)目的時(shí)候報(bào)錯(cuò)的,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • mybatisplus根據(jù)條件只更新一個(gè)字段的實(shí)現(xiàn)

    mybatisplus根據(jù)條件只更新一個(gè)字段的實(shí)現(xiàn)

    MyBatis-Plus提供使用update方法結(jié)合Wrapper來(lái)指定更新條件和要更新的字段,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • java編程實(shí)現(xiàn)并查集的路徑壓縮代碼詳解

    java編程實(shí)現(xiàn)并查集的路徑壓縮代碼詳解

    這篇文章主要介紹了java編程實(shí)現(xiàn)并查集的路徑壓縮代碼詳解,具有一定借鑒價(jià)值,需要的朋友可以參考。
    2017-11-11
  • SpringBoot?Admin集成診斷利器Arthas示例實(shí)現(xiàn)

    SpringBoot?Admin集成診斷利器Arthas示例實(shí)現(xiàn)

    這篇文章主要為大家介紹了SpringBoot?Admin集成診斷利器Arthas示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Java的分支結(jié)構(gòu)與循環(huán)你知道多少

    Java的分支結(jié)構(gòu)與循環(huán)你知道多少

    這篇文章主要為大家詳細(xì)介紹了Java的分支結(jié)構(gòu)與循環(huán),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-02-02

最新評(píng)論

济宁市| 西充县| 钦州市| 东海县| 泗阳县| 通化县| 肥西县| 屯门区| 南华县| 苍山县| 五家渠市| 阿荣旗| 修文县| 湖南省| 临邑县| 博乐市| 澄江县| 达日县| 建始县| 汉沽区| 威远县| 梓潼县| 阿克陶县| 东兰县| 准格尔旗| 商洛市| 库伦旗| 长宁区| 松阳县| 白朗县| 成都市| 台南县| 四会市| 贵德县| 宝坻区| 顺义区| 丰原市| 额尔古纳市| 酉阳| 高尔夫| 靖宇县|