Java基礎-完成局域網內溝通軟件的開發

目錄

案例要求:

實現思路:

itheima-chat-server包

src

com.itheima

Constant類:

Server類:

ServerReaderThread類:

itheima-chat-system包

src

com.itheima.ui

ChatEntryFrame類:

ClientChatFrame類:

ClientReaderThread類:

Constant類:

APP啟動類:

總結:


案例要求:

實現思路:

itheima-chat-server包

src

com.itheima
Constant類:
package com.itheima;public class Constant {public static final int PORT = 6666;
}
Server類:
package com.itheima;import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;public class Server {// 定義一個集合容器存儲所有登錄進來的客戶端管道,以便將來群發消息給他們.// 定義一個Map集合,鍵是存儲客戶端的管道,值是這個管道的用戶名稱。public static final Map<Socket, String> onLineSockets = new HashMap<>();public static void main(String[] args) {System.out.println("啟動服務端系統.....");try {// 1、注冊端口。ServerSocket serverSocket = new ServerSocket(Constant.PORT);// 2、主線程負責接受客戶端的連接請求while (true) {// 3、調用accept方法,獲取到客戶端的Socket對象System.out.println("等待客戶端的連接.....");Socket socket = serverSocket.accept();// 把這個管道交給一個獨立的線程來處理:以便支持很多客戶端可以同時進來通信。new ServerReaderThread(socket).start();System.out.println("一個客戶端連接成功.....");}} catch (Exception e) {e.printStackTrace();}}
}
ServerReaderThread類:
package com.itheima;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;public class ServerReaderThread extends Thread{private Socket socket;public ServerReaderThread(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {// 接收的消息可能有很多種類型:1、登錄消息(包含昵稱) 2、群聊消息 3、私聊消息// 所以客戶端必須聲明協議發送消息// 比如客戶端先發1,代表接下來是登錄消息。// 比如客戶端先發2,代表接下來是群聊消息。// 先從socket管道中接收客戶端發送來的消息類型編號DataInputStream dis = new DataInputStream(socket.getInputStream());while (true) {int type = dis.readInt(); // 1、2、3switch (type){case 1:// 客戶端發來了登錄消息,接下來要接收昵稱數據,再更新全部在線客戶端的在線人數列表。String nickname = dis.readUTF();// 把這個登錄成功的客戶端socket存入到在線集合。Server.onLineSockets.put(socket, nickname);// 更新全部客戶端的在線人數列表updateClientOnLineUserList();break;case 2:// 客戶端發來了群聊消息,接下來要接收群聊消息內容,再把群聊消息轉發給全部在線客戶端。String msg = dis.readUTF();sendMsgToAll(msg);break;case 3:// 客戶端發來了私聊消息,接下來要接收私聊消息內容,再把私聊消息轉發給指定客戶端。break;}}} catch (Exception e) {System.out.println("客戶端下線了:"+ socket.getInetAddress().getHostAddress());Server.onLineSockets.remove(socket); // 把下線的客戶端socket從在線集合中移除updateClientOnLineUserList(); // 下線了用戶也需要更新全部客戶端的在線人數列表。}}// 給全部在線socket推送當前客戶端發來的消息private void sendMsgToAll(String msg) {// 一定要拼裝好這個消息,再發給全部在線socket.StringBuilder sb = new StringBuilder();String name = Server.onLineSockets.get(socket);// 獲取當前時間LocalDateTime now = LocalDateTime.now();DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss EEE a");String nowStr = dtf.format(now);String msgResult = sb.append(name).append(" ").append(nowStr).append("\r\n").append(msg).append("\r\n").toString();// 推送給全部客戶端socketfor (Socket socket : Server.onLineSockets.keySet()) {try {// 3、把集合中的所有用戶名稱,通過socket管道發送給客戶端DataOutputStream dos = new DataOutputStream(socket.getOutputStream());dos.writeInt(2); // 1代表告訴客戶端接下來是在線人數列表信息  2 代表發的是群聊消息dos.writeUTF(msgResult);dos.flush(); // 刷新數據!} catch (Exception e) {e.printStackTrace();}}}private void updateClientOnLineUserList() {// 更新全部客戶端的在線人數列表// 拿到全部在線客戶端的用戶名稱,把這些名稱轉發給全部在線socket管道。// 1、拿到當前全部在線用戶昵稱Collection<String> onLineUsers = Server.onLineSockets.values();// 2、把這個集合中的所有用戶都推送給全部客戶端socket管道。for (Socket socket : Server.onLineSockets.keySet()) {try {// 3、把集合中的所有用戶名稱,通過socket管道發送給客戶端DataOutputStream dos = new DataOutputStream(socket.getOutputStream());dos.writeInt(1); // 1代表告訴客戶端接下來是在線人數列表信息  2 代表發的是群聊消息dos.writeInt(onLineUsers.size()); // 告訴客戶端,接下來要發多少個用戶名稱for (String onLineUser : onLineUsers) {dos.writeUTF(onLineUser);}dos.flush();} catch (Exception e) {e.printStackTrace();}}}
}

itheima-chat-system包

src

com.itheima.ui
ChatEntryFrame類:
package com.itheima.ui;import javax.swing.*;
import java.awt.*;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;public class ChatEntryFrame extends JFrame {private JTextField nicknameField;private JButton enterButton;private JButton cancelButton;private Socket socket; // 記住當前客戶端系統的通信管道public ChatEntryFrame() {setTitle("局域網聊天室");setSize(350, 150);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setLocationRelativeTo(null);setResizable(false); // 禁止調整大小// 設置背景顏色getContentPane().setBackground(Color.decode("#F0F0F0"));// 創建主面板并設置布局JPanel mainPanel = new JPanel(new BorderLayout());mainPanel.setBackground(Color.decode("#F0F0F0"));add(mainPanel);// 創建頂部面板JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));topPanel.setBackground(Color.decode("#F0F0F0"));// 標簽和文本框JLabel nicknameLabel = new JLabel("昵稱:");nicknameLabel.setFont(new Font("楷體", Font.BOLD, 16));nicknameField = new JTextField(10);nicknameField.setFont(new Font("楷體", Font.PLAIN, 16));nicknameField.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.GRAY),BorderFactory.createEmptyBorder(5, 5, 5, 5)));topPanel.add(nicknameLabel);topPanel.add(nicknameField);mainPanel.add(topPanel, BorderLayout.NORTH);// 按鈕面板JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));buttonPanel.setBackground(Color.decode("#F0F0F0"));enterButton = new JButton("登錄");enterButton.setFont(new Font("楷體", Font.BOLD, 16));enterButton.setBackground(Color.decode("#007BFF"));enterButton.setForeground(Color.WHITE);enterButton.setBorderPainted(false);enterButton.setFocusPainted(false);cancelButton = new JButton("取消");cancelButton.setFont(new Font("楷體", Font.BOLD, 16));cancelButton.setBackground(Color.decode("#DC3545"));cancelButton.setForeground(Color.WHITE);cancelButton.setBorderPainted(false);cancelButton.setFocusPainted(false);buttonPanel.add(enterButton);buttonPanel.add(cancelButton);mainPanel.add(buttonPanel, BorderLayout.SOUTH);// 添加監聽器enterButton.addActionListener(e -> {String nickname = nicknameField.getText(); // 獲取昵稱nicknameField.setText("");if (!nickname.isEmpty()) {try {login(nickname);// 進入聊天室邏輯: 啟動聊天界面。把昵稱傳給聊天界面。new ClientChatFrame(nickname, socket);this.dispose(); // 關閉登錄窗口} catch (Exception ex) {ex.printStackTrace();}} else {JOptionPane.showMessageDialog(this, "請輸入昵稱!");}});cancelButton.addActionListener(e -> System.exit(0));this.setVisible(true); // 顯示窗口}public void login(String nickname) throws Exception {// 立即發送登錄消息給服務端程序。// 1、創建Socket管道請求與服務端的socket鏈接socket = new Socket(Constant.SERVER_IP, Constant.SERVER_PORT );// 2、立即發送消息類型1 和自己的昵稱給服務端DataOutputStream dos = new DataOutputStream(socket.getOutputStream());dos.writeInt(1); // 消息類型 登錄dos.writeUTF(nickname);dos.flush();}public static void main(String[] args) {new ChatEntryFrame();}
}
ClientChatFrame類:
package com.itheima.ui;import javax.swing.*;
import java.awt.*;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;public class ChatEntryFrame extends JFrame {private JTextField nicknameField;private JButton enterButton;private JButton cancelButton;private Socket socket; // 記住當前客戶端系統的通信管道public ChatEntryFrame() {setTitle("局域網聊天室");setSize(350, 150);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setLocationRelativeTo(null);setResizable(false); // 禁止調整大小// 設置背景顏色getContentPane().setBackground(Color.decode("#F0F0F0"));// 創建主面板并設置布局JPanel mainPanel = new JPanel(new BorderLayout());mainPanel.setBackground(Color.decode("#F0F0F0"));add(mainPanel);// 創建頂部面板JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));topPanel.setBackground(Color.decode("#F0F0F0"));// 標簽和文本框JLabel nicknameLabel = new JLabel("昵稱:");nicknameLabel.setFont(new Font("楷體", Font.BOLD, 16));nicknameField = new JTextField(10);nicknameField.setFont(new Font("楷體", Font.PLAIN, 16));nicknameField.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.GRAY),BorderFactory.createEmptyBorder(5, 5, 5, 5)));topPanel.add(nicknameLabel);topPanel.add(nicknameField);mainPanel.add(topPanel, BorderLayout.NORTH);// 按鈕面板JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));buttonPanel.setBackground(Color.decode("#F0F0F0"));enterButton = new JButton("登錄");enterButton.setFont(new Font("楷體", Font.BOLD, 16));enterButton.setBackground(Color.decode("#007BFF"));enterButton.setForeground(Color.WHITE);enterButton.setBorderPainted(false);enterButton.setFocusPainted(false);cancelButton = new JButton("取消");cancelButton.setFont(new Font("楷體", Font.BOLD, 16));cancelButton.setBackground(Color.decode("#DC3545"));cancelButton.setForeground(Color.WHITE);cancelButton.setBorderPainted(false);cancelButton.setFocusPainted(false);buttonPanel.add(enterButton);buttonPanel.add(cancelButton);mainPanel.add(buttonPanel, BorderLayout.SOUTH);// 添加監聽器enterButton.addActionListener(e -> {String nickname = nicknameField.getText(); // 獲取昵稱nicknameField.setText("");if (!nickname.isEmpty()) {try {login(nickname);// 進入聊天室邏輯: 啟動聊天界面。把昵稱傳給聊天界面。new ClientChatFrame(nickname, socket);this.dispose(); // 關閉登錄窗口} catch (Exception ex) {ex.printStackTrace();}} else {JOptionPane.showMessageDialog(this, "請輸入昵稱!");}});cancelButton.addActionListener(e -> System.exit(0));this.setVisible(true); // 顯示窗口}public void login(String nickname) throws Exception {// 立即發送登錄消息給服務端程序。// 1、創建Socket管道請求與服務端的socket鏈接socket = new Socket(Constant.SERVER_IP, Constant.SERVER_PORT );// 2、立即發送消息類型1 和自己的昵稱給服務端DataOutputStream dos = new DataOutputStream(socket.getOutputStream());dos.writeInt(1); // 消息類型 登錄dos.writeUTF(nickname);dos.flush();}public static void main(String[] args) {new ChatEntryFrame();}
}
ClientReaderThread類:
package com.itheima.ui;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;public class ClientReaderThread extends Thread{private Socket socket;private DataInputStream dis;private ClientChatFrame win;public ClientReaderThread( Socket socket, ClientChatFrame win) {this.win = win;this.socket = socket;}@Overridepublic void run() {try {// 接收的消息可能有很多種類型:1、在線人數更新的數據 2、群聊消息dis = new DataInputStream(socket.getInputStream());while (true) {int type = dis.readInt(); // 1、2、3switch (type){case 1:// 服務端發來的在線人數更新消息updateClientOnLineUserList();break;case 2:// 服務端發送來的群聊消息getMsgToWin();break;}}} catch (Exception e) {e.printStackTrace();}}private void getMsgToWin() throws Exception {// 獲取群聊消息String msg = dis.readUTF();win.setMsgToWin(msg);}// 更新客戶端的在線用戶列表private void updateClientOnLineUserList() throws Exception {// 1、讀取有多少個在線用戶int count = dis.readInt();// 2、循環控制讀取多少個用戶信息。String[] names = new String[count];for (int i = 0; i < count; i++) {// 3、讀取每個用戶的信息String nickname = dis.readUTF();// 4、將每個用戶的信息添加到數組names[i] = nickname;}// 5、將集合中的數據展示到窗口上win.updateOnlineUsers(names);}}

Constant類:

package com.itheima.ui;public class Constant {public static final String SERVER_IP = "127.0.0.1";public static final int SERVER_PORT = 6666;
}

APP啟動類:

import com.itheima.ui.ChatEntryFrame;public class App {public static void main(String[] args) {new ChatEntryFrame(); // 啟動登錄界面}
}


總結:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/92736.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/92736.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/92736.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

windows內核研究(內存管理-線性地址的管理)

內存管理線性地址的管理 進程空間的地址劃分分區x86 32位Windows空指針賦值區0x00000000 - 0x0000FFFF用戶模式區0x00010000 - 0x7FFEFFFF64KB禁入區0x7FFF0000 - 0x7FFFFFFF內核0x80000000 - 0xFFFFFFFF線性地址有4GB&#xff0c;但是并不是所有的地方都能訪問&#xff08;這里…

【問題解決】使用patch-package修改node-models中的源碼

文章目錄一、應用場景二、patch-package 和 postinstallpatch-packagepostinstall三、操作步驟1、使用yarn安裝patch-package和postinstall-postinstall2、修改package.json3、修改node-model中源碼、保存。4、找到修改文件對應的包名5、使用git將新增的patches文件同步到倉庫6…

當配置項只支持傳入數字,即無法指定單位為rem,需要rem轉px

您好&#xff01;針對您 Vue 3 Element Plus 的技術棧&#xff0c;要優雅且符合大廠規范地解決這個問題&#xff0c;最佳實踐是創建一個響應式的 Composition API (組合式函數)。 這個方法完全遵循 Vue 3 的設計哲學&#xff0c;具有高內聚、低耦合、可復用、類型安全&#xf…

谷歌搜索 sg_ss 逆向分析

聲明: 本文章中所有內容僅供學習交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包內容、敏感網址、數據接口等均已做脫敏處理&#xff0c;嚴禁用于商業用途和非法用途&#xff0c;否則由此產生的一切后果均與作者無關&#xff01;部分python代碼sg_ss cp.call(get_sg_…

一個“加鎖無效“的詭異現象

加鎖了還出問題&#xff1f;從"點擊過快"到"狀態可控"&#xff1a;多線程共享變量的并發陷阱與實戰對策詳情如下&#xff1a;在服務端開發中&#xff0c;多線程并發處理客戶端請求是提升系統吞吐量的常見手段。最近有位開發者朋友遇到了一個令人費解的問題…

液體泄漏識別誤報率↓76%:陌訊多模態融合算法實戰解析

原創聲明本文為原創技術解析&#xff0c;核心技術參數與架構設計引用自《陌訊技術白皮書》&#xff0c;禁止未經授權的轉載與篡改。一、行業痛點&#xff1a;液體泄漏識別的現實挑戰在化工生產、食品加工、倉儲物流等場景中&#xff0c;液體泄漏的實時監測是保障安全生產的關鍵…

Y9000P跑開源模型(未完成)

環境信息 1、Y9000筆記本 2、1T空白硬盤 3、ubunut24.04桌面版 一、環境初始化 第一部分&#xff1a;系統初始化 1、安裝基礎軟件 apt-get update apt-get -y install openssh-server openssh-client apt-utils freeipmi ipmitool sshpass ethtool zip unzip nano less git ne…

ARM體系結構

ARM體系結構 編程原理 從源代碼到CPU執行過程 #mermaid-svg-M4xemCxDjIQVNNnW {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:14px;fill:#333;}#mermaid-svg-M4xemCxDjIQVNNnW .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mer…

基于SpringBoot的高校社團管理系統的設計與實現(代碼+LW文檔+遠程運行)

&#x1f4af;博主&#xff1a;?全網擁有50W粉絲、博客專家、全棧領域優質創作者、平臺優質Java創作者、專注于Java技術領域和畢業項目實戰?&#x1f4af; &#x1f497;開發技術&#xff1a;SpringBoot、Vue、SSM、PHP、Nodejs、Python、爬蟲、數據可視化、小程序、安卓app、…

F5發布業界首創集成式應用交付與安全平臺,開啟ADC 3.0新時代

在數字化轉型加速與AI技術蓬勃發展的今天&#xff0c;企業對應用性能與安全的需求正經歷革命性變革。傳統應用架構已難以滿足現代混合多云環境與AI驅動型業務場景的嚴苛要求。全球領先的應用安全和交付服務提供商F5&#xff08;NASDAQ: FFIV&#xff09;&#xff0c;持續推動 F…

SELinux 入門指南

SELinux(Security-Enhanced Linux)是 Linux 內核的一個安全模塊&#xff0c;它提供了一種強制訪問控制&#xff08;Mandatory Access Control, MAC&#xff09;機制。與傳統的 Linux 自主訪問控制&#xff08;Discretionary Access Control, DAC&#xff09;不同&#xff0c;SE…

ARMv8 MMU頁表格式及地址轉換過程分析

1.簡介 CPU發出的虛擬地址經過MMU轉換后得到物理地址&#xff0c;然后使用物理地址訪問真實的硬件。虛擬地址和物理地址的映射關系保存在頁表中&#xff0c;MMU需要遍歷頁表&#xff0c;才能將虛擬地址轉換成物理地址。ARM64現在有兩種大小的頁表描述符&#xff0c;分別是ARMv8…

數據結構---二叉樹(概念、特點、分類、特性、讀取順序、例題)、gdb調試指令、時間復雜度(概念、大O符號法、分類)

一、二叉樹1、樹1&#xff09;概念 樹是 n(n > 0) 個結點的有限集合。若 n0 &#xff0c;為空樹。在任意一個非空樹中&#xff1a;&#xff08;1&#xff09;有且僅有一個特定的根結點&#xff1b;&#xff08;2&#xff09;當 n>1 時&#xff0c;其余結點可分為 …

安全基礎DAY1-安全概述

信息安全現狀及挑戰常見術語信息安全的脆弱性及常見攻擊網絡環境的開放性其實就是人人可以上網&#xff0c;網上零成本。協議棧自身的脆弱性及常見攻擊協議棧自身的脆弱性常見安全風險網絡的基本攻擊模式物理層--物理攻擊前置知識 1.打開Apache服務 cd /etc/init.d ./apache2 s…

Claude Code 的核心能力與架構解析

技術分析介紹&#xff1a;Claude Code 的核心能力與架構解析一、概述 Claude Code 是由 Anthropic 推出的面向開發者的智能編碼助手&#xff0c;它不僅僅是一個代碼生成工具&#xff0c;更是一個具備記憶、工具調用、自主規劃和環境感知能力的“智能代理”&#xff08;Agentic …

Mac 電腦放在環境變量中的通用腳本

mac電腦下放在環境變量中&#xff0c;方便提高效率執行 注&#xff1a;相關路徑需要根據實際情況進行更新 需要在 .bash_profile 文件中定義如下&#xff08;路徑需要做實際替換&#xff09;&#xff1a; source $HOME/software/scripts/base_profile.sh source $HOME/software…

UE藍圖節點Add Impulse和Add Torque in Radians

???????Add Impulse&#xff1a;對剛體施加一次性的線性脈沖&#xff08;瞬時改變量&#xff09;&#xff0c;改變速度&#xff08;與質量有關&#xff0c;除非你勾 bVelChange&#xff09;。Add Torque (in Radians)&#xff1a;對剛體施加轉矩/旋轉力&#xff08;向量…

大型語言模型幻覺檢測與緩解技術研究綜述

摘要 本文系統綜述了大型語言模型(LLMs)中的幻覺現象及其檢測與緩解技術。研究首先從認知機制角度分析了幻覺產生的理論根源&#xff0c;包括模型對語言先驗的過度依賴、訓練數據偏差以及推理過程中的信息衰減等問題。在技術層面&#xff0c;綜述將現有方法歸納為三類&#xff…

【數據結構初階】--二叉樹(二)

&#x1f618;個人主頁&#xff1a;Cx330? &#x1f440;個人簡介&#xff1a;一個正在努力奮斗逆天改命的二本覺悟生 &#x1f4d6;個人專欄&#xff1a;《C語言》《LeetCode刷題集》《數據結構-初階》 前言&#xff1a;上篇博客我們學習了有關樹的概念和相關術語的介紹&…

jmm 指令重排 緩存可見性 Volatile 內存屏障

CPU指令重排 CPU指令重排是指CPU為了提高指令執行效率&#xff0c;可能會對指令的執行順序進行優化&#xff0c;使得&#xff08;單線程下&#xff09;指令的實際執行順序與代碼中的順序不同&#xff0c;但結果是一致的。 這種優化是通過亂序執行和緩存讀寫重排來實現的。 亂序…