当前位置: 首页 > article >正文

最新版 Java 网络编程经典案例:IM 系统、网络拷贝|万字笔记

文章目录

  • 1.网络聊天小程序
    • 1.1 设计目标
    • 1.2 程序功能概述
    • 1.3 详细实现步骤
      • 1.3.1. 创建服务器端
      • 1.3.2. 创建客户端
    • 1.4 总结
  • 2.网络聊天小程序(GUI)
    • 2.1 设计目标
    • 2.2 程序功能概述
    • 2.3 详细实现步骤
      • 2.3.1. 创建服务器端
      • 2.3.2. 创建客户端的 Swing 界面
    • 2.4 总结
  • 3. 聊天室添加表情功能
    • 服务端代码 (ChatServer.java)
    • 客户端代码 (ChatClient.java)
  • 4.文件拷贝器概述
    • 4.1程序设计
      • 4.1.1. GUI界面设计(Swing)
      • 4.1.2. 文件拷贝任务(多线程)
      • 4.1.3. 线程池的使用
    • 4.2 总结
  • 5.文件拷贝器
    • 5.1. **设计目的与问题背景**
    • 5.2. **功能描述**
    • 5.3. **GUI设计与布局**
      • 5.3.1 GUI组件
    • 5.4. **程序设计与实现**
      • 5.4.1 主程序结构
    • 5.5. **详细解读**
      • 5.5.1 主程序结构
      • 5.5.2 文件拷贝与多线程
    • 5.6. **总结**
  • 6.文件拷贝器设计与实现
    • 6.1. 项目结构
    • 6.2. 实现步骤
      • 6.2.1 GUI部分
      • 6.2.2 代码解读
    • 6.3 代码改进
      • 6.3.1 代码改进解读
    • 6.4 总结

1.网络聊天小程序

1.1 设计目标

设计一个基于Java的网络聊天小程序,该程序能够通过网络让多个客户端与服务器通信,并实现基本的聊天功能。这个项目旨在让学生更好地理解和运用以下Java编程知识点:

  1. Java网络编程:实现客户端与服务器之间的通信。
  2. Lambda表达式:简化代码,尤其是在处理集合时。
  3. Map集合:用于存储和管理客户端与其相关信息。
  4. List集合:管理聊天室中的消息记录。
  5. 多线程:支持多个客户端同时连接和发送消息。
  6. 线程池:提高资源利用率和管理线程。

1.2 程序功能概述

  1. 服务器端
    • 监听客户端的连接。
    • 为每个连接创建一个独立的线程处理。
    • 将消息广播给所有已连接的客户端。
  2. 客户端
    • 连接到服务器。
    • 发送消息到服务器。
    • 接收并显示来自其他客户端的消息。

1.3 详细实现步骤

1.3.1. 创建服务器端

目的:实现服务器端,能够处理多个客户端的连接请求,并将消息广播给所有客户端。

步骤

  • Socket和ServerSocket
    • 使用ServerSocket监听特定端口,等待客户端连接。
    • 使用Socket对象来处理每个客户端的连接。
  • 多线程
    • 每当有客户端连接时,服务器创建一个新的线程来处理这个客户端的请求,确保服务器能够同时处理多个客户端的连接。
  • 线程池
    • 使用Executors.newFixedThreadPool()创建一个固定大小的线程池,以避免服务器因大量线程而崩溃。
  • Map集合
    • 使用Map<String, Socket>来存储已连接客户端的用户名和Socket,便于广播消息时遍历所有客户端。
  • Lambda表达式
    • 使用Lambda表达式简化对集合的操作,如在广播消息时遍历Map集合。

代码示例

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;

public class ChatServer {
   
    // 服务器监听的端口号
    private static final int PORT = 12345;
    
    // 使用ConcurrentHashMap来存储客户端名称和对应的Socket,确保线程安全
    private static Map<String, Socket> clients = new ConcurrentHashMap<>();
    
    // 创建一个固定大小的线程池来处理客户端连接
    private static ExecutorService pool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
   
        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
   
            System.out.println("聊天服务器已启动...");

            // 持续监听新的客户端连接
            while (true) {
   
                Socket clientSocket = serverSocket.accept();
                // 每个新连接都交给线程池处理
                pool.execute(new ClientHandler(clientSocket));
            }
        } catch (IOException e) {
   
            e.printStackTrace();
        }
    }

    // 内部类,处理每个客户端的连接
    private static class ClientHandler implements Runnable {
   
        private Socket clientSocket;
        private String clientName;

        public ClientHandler(Socket socket) {
   
            this.clientSocket = socket;
        }

        @Override
        public void run() {
   
            try (BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                 PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {
   

                // 读取客户端的名称
                clientName = in.readLine();
                // 将客户端添加到在线列表中
                clients.put(clientName, clientSocket);
                // 广播客户端加入的消息
                broadcastMessage("Server", clientName + " 加入了聊天室!");

                String message;
                // 持续读取客户端消息并广播
                while ((message = in.readLine()) != null) {
   
                    broadcastMessage(clientName, message);
                }
            } catch (IOException e) {
   
                e.printStackTrace();
            } finally {
   
                // 客户端断开连接时的清理工作
                if (clientName != null) {
   
                    clients.remove(clientName);
                    broadcastMessage("Server", clientName + " 离开了聊天室.");
                }
            }
        }

        // 广播消息到所有客户端
        private void broadcastMessage(String sender, String message) {
   
            clients.forEach((name, socket) -> {
   
                try {
   
                    PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
                    out.println(sender + ": " + message);
                } catch (IOException e) {
   
                    e.printStackTrace();
                }
            });
        }
    }
}

代码解释:

  • 端口设置:PORT变量定义了服务器监听的端口号。
  • 客户端管理:clients是一个ConcurrentHashMap,用于存储客户端的名称和对应的Socket,确保在多线程环境下操作安全。
  • 线程池:使用ExecutorService创建一个固定大小的线程池,避免每个新连接都创建新线程。
  • 主方法
    • 启动服务器并监听指定端口。
    • 接受客户端连接后,使用线程池执行ClientHandler来处理每个客户端。
  • ClientHandler类
    • 实现Runnable接口,每个客户端连接时启动一个新线程。
    • 从客户端读取名称,并将其加入到在线客户端列表。
    • 持续读取客户端发送的消息,并通过broadcastMessage方法发送给所有其他客户端。
  • 广播方法
    • broadcastMessage方法遍历所有在线客户端,将消息发送给每个客户端。

1.3.2. 创建客户端

目的:实现客户端,能够连接服务器,发送和接收消息。

步骤

  • Socket
    • 使用Socket对象连接到服务器。
  • 多线程
    • 使用独立线程处理从服务器接收的消息,以便客户端能够同时发送和接收消息。
  • List集合
    • 存储并管理客户端的聊天记录。

代码示例

import java.io.*;
import java.net.*;
import java.util.concurrent.*;

public class ChatClient {
   
    // 服务器地址和端口
    private static final String SERVER_ADDRESS = "localhost";
    private static final int SERVER_PORT = 12345;
    
    // 创建一个线程池,用于处理消息接收
    private static ExecutorService pool = Executors.newFixedThreadPool(2);

    public static void main(String[] args) {
   
        try (
            // 创建与服务器的Socket连接
            Socket socket = new Socket(SERVER_ADDRESS, SERVER_PORT);
            
            // 读取服务器发送的消息
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            
            // 向服务器发送消息
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            
            // 从控制台读取用户输入
            BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in))
        ) {
   
            // 提示用户输入名字
            System.out.print("请输入您的名字: ");
            String name = keyboard.readLine();
            // 将名字发送给服务器
            out.println(name);

            // 使用线程池启动一个线程来接收服务器消息
            pool.execute(() -> {
   
                try {
   
                    String message;
                    // 持续读取服务器消息并打印
                    while ((message = in.readLine()) != null) {
   
                        System.out.println(message);
                    }
                } catch (IOException e) {
   
                    e.printStackTrace();
                }
            });

            // 主线程用于发送消息给服务器
            String message;
            // 持续读取用户输入并发送
            while ((message = keyboard.readLine()) != null) {
   
                out.println(message);
            }

        } catch (IOException e) {
   
            e.printStackTrace();
        }
    }
}

代码解释:

  • 服务器连接:SERVER_ADDRESS和SERVER_PORT定义了客户端将要连接的服务器信息。
  • 线程池:pool用于管理接收消息的线程,避免主线程阻塞。
  • 主方法
    • 使用try-with-resources确保所有资源在使用后被关闭。
    • Socket socket:创建与服务器的Socket连接。
    • BufferedReader in:从服务器读取消息。
    • PrintWriter out:向服务器发送消息。
    • BufferedReader keyboard:从控制台读取用户输入。
  • 用户输入和连接
    • 提示用户输入名字并发送给服务器。
  • 消息接收
    • 使用线程池启动一个新线程来持续读取服务器消息并打印到控制台。
  • 消息发送
    • 主线程持续读取用户输入并发送到服务器。

1.4 总结

这个网络聊天小程序将Java网络编程、多线程、线程池、集合框架以及Lambda表达式结合在一起,为学生提供了一个综合性的学习案例。通过该程序,学生能够深入理解如何在实际应用中使用这些编程概念,并学会设计和实现一个多用户的网络应用。

2.网络聊天小程序(GUI)

2.1 设计目标

设计一个基于 Java 的网络聊天小程序,并使用 Swing 来实现图形用户界面(GUI)。该项目旨在帮助学生掌握以下Java编程知识点:

  1. Java 网络编程:实现客户端与服务器之间的通信。
  2. Lambda 表达式:简化代码逻辑。
  3. Map 集合:管理客户端与其相关信息。
  4. List 集合:存储和管理消息记录。
  5. 多线程:支持多个客户端同时连接和发送消息。
  6. 线程池:有效管理和分配服务器的线程资源。
  7. Swing:创建客户端的图形用户界面。

2.2 程序功能概述

  1. 服务器端
    • 监听客户端的连接。
    • 为每个连接创建一个独立线程处理。
    • 将消息广播给所有已连接的客户端。
  2. 客户端
    • 使用 Swing 创建一个简单的聊天界面。
    • 连接到服务器。
    • 发送消息并在界面上显示接收到的消息。

2.3 详细实现步骤

2.3.1. 创建服务器端

目的:实现服务器端,处理多个客户端连接,并将消息广播给所有客户端。

步骤

  • Socket 和 ServerSocket
    • 使用ServerSocket监听指定端口,等待客户端连接。
    • 每个连接使用Socket对象进行处理。
  • 多线程
    • 每当有客户端连接时,服务器创建一个新线程处理该客户端。
  • 线程池
    • 使用ExecutorService创建一个固定大小的线程池,以提高资源利用率并管理并发线程。
  • Map 集合
    • 使用Map<String, Socket>存储每个已连接客户端的用户名及其对应的 Socket 对象,方便消息广播。
  • Lambda 表达式
    • 使用 Lambda 表达式简化广播消息时对集合的操作。

代码示例

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;

public class ChatServer {
   
    // 服务器监听的端口号
    private static final int PORT = 12345;
    
    // 使用 ConcurrentHashMap 来存储客户端名称和对应的 Socket,确保线程安全
    private static Map<String, Socket> clients = new ConcurrentHashMap<>();
    
    // 创建一个固定大小的线程池来处理客户端连接
    private static ExecutorService pool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
   
        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
   
            System.out.println("聊天服务器已启动...");
            
            // 持续监听新的客户端连接
            while (true) {
   
                Socket clientSocket = serverSocket.accept();
                // 每个新连接都交给线程池处理
                pool.execute(new ClientHandler(clientSocket));
            }
        } catch (IOException e) {
   
            e.printStackTrace();
        }
    }

    // 内部类,处理每个客户端的连接
    private static class ClientHandler implements Runnable {
   
        private Socket clientSocket;
        private String clientName;

        public ClientHandler(Socket socket) {
   
            this.clientSocket = socket;
        }

        @Override
        public void run() {
   
            try (BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                 PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {
   

                // 读取客户端的名称
                clientName = in.readLine();
                // 将客户端添加到在线列表中
                clients.put(clientName, clientSocket);
                // 广播客户端加入的消息
                broadcastMessage("Server", clientName + " 加入了聊天室!");

                String message;
                // 持续读取客户端消息并广播
                while ((message = in.readLine()) != null) {
   
                    broadcastMessage(clientName, message);
                }
            } catch (IOException e) {
   
                e.printStackTrace();
            } finally {
   
                // 客户端断开连接时的清理工作
                if (clientName != null) {
   
                    clients.remove(clientName);
                    broadcastMessage("Server", clientName + " 离开了聊天室.");
                }
            }
        }

        // 广播消息到所有客户端
        private void broadcastMessage(String sender, String message) {
   
            clients.forEach((name, socket) -> {
   
                try {
   
                    PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
                    out.println(sender + ": " + message);
                } catch (IOException e) {
   
                    e

http://www.kler.cn/news/294835.html

相关文章:

  • 软件工程-图书管理系统的概要设计
  • 网络层ip协议
  • echarts 水平柱图 科技风
  • 单北斗新时代,遨游通讯四款防爆手机筑牢安全防线
  • Java数组(详解版)
  • Windows .NET8 实现 远程一键部署,几秒完成发布,提高效率 - CICD
  • Rust : 从事量化的生态现状与前景
  • 漫谈设计模式 [17]:状态模式
  • 调研-libevent
  • VitePress 自定义 CSS 指南
  • docker基础命令总结
  • 流程图符号速查:快速掌握流程图绘制要点
  • Kafka【十二】消费者拉取主题分区的分配策略
  • NISP 一级 —— 考证笔记合集
  • RISC-V (十二)系统调用
  • python网络爬虫(五)——爬取天气预报
  • 风趣图解LLMs RAG的15种设计模式-第一课
  • 自然语言处理系列六十二》神经网络算法》MLP多层感知机算法
  • 【C/C++】web服务器项目开发总结【请求 | 响应 | CGI】
  • 活动系统开发之采用设计模式与非设计模式的区别-非设计模式
  • Java stream使用与执行原理
  • 通信工程学习:什么是SSB单边带调制、VSB残留边带调制、DSB抑制载波双边带调制
  • Web前端主流的框架详解
  • 基于大数据的科研热点分析与挖掘系统
  • 数学建模_数据预处理流程(全)
  • 命名空间,using声明,指令与作用域,重载与namespace
  • 智慧工地解决方案-2
  • 架构全景视图
  • lxml官方入门教程(The lxml.etree Tutorial)翻译
  • 超越IP-Adapter!阿里提出UniPortrait,可通过文本定制生成高保真的单人或多人图像。