Java 网络通信编程(1):服务器多任务连接+广播消息实现

        在之前的文章中,我们学习了网络编程的基础知识。今天,我们将进入实践阶段,动手搭建自定义的服务器和客户端,重点实现服务器的多任务连接与消息广播功能。

1.自定义客户端(MClient)

        首先,我们来搭建自定义客户端,与运行在本地(127.0.0.1),端口为2000的服务器进行连接,并获取它的输入输出流。

Socket socket = new Socket("127.0.0.1", 2000); System.out.println("连接服务器"); is = socket.getInputStream(); os = socket.getOutputStream();

        之后考虑发送与读取消息,将它们分别包装成方法体。

  • 发送消息时需注意在字符串末尾拼接换行让每条信息正确排版。通过调用输出流的 write() 方法,存储由字符串转为字节数组的消息,再用 flush() 方法确保强制写入。
  • 我们可以利用一定长度的缓存区来读取消息,read() 方法会读取消息并存储到括号里的 bytes 数组中,用 String msg = new String(bytes);定义msg,可以将 byte 数组直接转为字符串,最后通过 trim() 方法返回消去多余空位的字符串。
//发送消息方法体 public void sendMsg(String msg)throws Exception{ String str = msg+"\r\n";//拼接换行 os.write(str.getBytes()); os.flush(); } //读取消息方法体 public String readMsg()throws Exception{ byte[] bytes = new byte[1024];//保存消息的缓存区 is.read(bytes); String msg = new String(bytes);//将 byte 数组转为字符串 return msg.trim();//去除空位 }

        由于客户端在发送消息的同时需要实时接收服务端的消息,我们应该开启一个独立线程。接收消息则需要从控制台读取对应的每一行输入。

 //启动线程来实时读取服务器发来的消息 new Thread(new Runnable() { @Override public void run() { while (true){ String str; try { str = readMsg(); } catch (Exception e) { throw new RuntimeException(e); } System.out.println("server:"+str); } } }).start();
 //发送消息 while (true) { Scanner scanner = new Scanner(System.in); String line = scanner.nextLine(); sendMsg(line); }

        整合后我们便可得到完整的自定义服务器代码。

mport java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.util.Scanner; public class MClient { public static void main(String[] args) { try { new MClient().startClient(); } catch (Exception e) { throw new RuntimeException(e); } } public InputStream is; public OutputStream os; public void startClient() throws Exception { Socket socket = new Socket("127.0.0.1", 2000); System.out.println("连接服务器"); is = socket.getInputStream(); os = socket.getOutputStream(); //启动线程来实时读取服务器发来的消息 new Thread(new Runnable() { @Override public void run() { while (true){ String str; try { str = readMsg(); } catch (Exception e) { throw new RuntimeException(e); } System.out.println("server:"+str); } } }).start(); //发送消息 while (true) { Scanner scanner = new Scanner(System.in); String line = scanner.nextLine(); sendMsg(line); } } //发送消息方法体 public void sendMsg(String msg)throws Exception{ String str = msg+"\r\n";//拼接换行 os.write(str.getBytes()); os.flush(); } //读取消息方法体 public String readMsg()throws Exception{ byte[] bytes = new byte[1024];//保存消息的缓存区 is.read(bytes); String msg = new String(bytes);//将 byte 数组转为字符串 return msg.trim();//去除空位 } } 

2.自定义服务端

2.1服务端框架(MServer)

        此处服务器担任“消息中转站”的角色,它要与多个客户端建立实时连接。对于实时性,结合之前搭建客户端的经验,我们容易想到利用线程。

        服务端对于每个连接过来的客户端,都会创建对应的 Socket 对象,为了实现消息广播功能,我们可以建立一个 ArrayList 集合用来存储 Socket 对象,就像一个 “在线客户端名单“。接着循环用 accept() 方法阻塞监听每一个连接过来的客户端,将其加入 ArrayList 集合。accept() 方法是阻塞的,服务器在连接到新客户端之前不会向下执行代码,为了不影响每个客户端,我们需要在下面启动该客户端独立、全新的线程来保持通信

import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; public class MServer { public static void main(String[] args) { try { new MServer().startServer(); } catch (Exception e) { throw new RuntimeException(e); } } public void startServer() throws Exception { ServerSocket server = new ServerSocket(2000); System.out.println("启动服务器"); ArrayList<Socket> list = new ArrayList<>(); //重复监听连接过来的客户端 while(true) { //阻塞监听连接过来的客户端 Socket socket = server.accept(); list.add(socket); //启动线程,保持通信 ServerThread serverThread = new ServerThread(socket,list); new Thread(serverThread).start(); } } }
2.2通信线程(ServerThread)

        搭建好服务器框架后我们来完善线程的具体内容。

        收发消息的方法体我们可以基本套用客户端的,但客户端的 sendMsg() 只需要操作唯一的一个输出流(客户端只连一个服务器,只有一个和服务器通信的输出流);而服务端的 sendMsg() 必须针对不同客户端的输出流(每个客户端对应一个独立的 Socket,每个 Socket 有专属的输出流),通过指定不同的 os 参数来区分要发送的目标客户端。

//发送消息方法体 public void sendMsg(OutputStream os, String msg) throws Exception { String str = msg + "\r\n";//拼接换行 os.write(str.getBytes()); os.flush(); } 

        通信线程对每个客户端都是独立的,因此构造函数中需要传入对应的 Socket 对象。同时为了实现向其他客户端发送消息的功能,需要其他客户端的 Socket 对象,因而传入 ArrayList 集合,所有线程共享同一个 ArrayList 集合。

public ServerThread(Socket socket, ArrayList<Socket> list) { this.socket = socket; this.list = list; //获取客户端输入输出流 try { is = socket.getInputStream(); os = socket.getOutputStream(); sendMsg(os, "客户端连接成功"); } catch (Exception e) { throw new RuntimeException(e); } }

        最后重写 run() 方法。对于广播功能,我们应该遍历 ArrayList ,对除去客户端本身的其他客户端,将消息写入输出流。

public void run() { while (true) { try { //接收信息 String msg = readMsg(); System.out.println("client:" + msg); //广播功能 for (Socket s : list) { if (s != socket) {//排除自己客户端 OutputStream os = s.getOutputStream(); sendMsg(os, msg); } } } catch (Exception e) { throw new RuntimeException(e); } } }

3.结果演示

        如此我们便实现了服务器多任务连接+广播消息。最后演示一下运行结果。

        启动服务器和多个客户端,均连接成功。服务器会向客户端发送”客户端连接成功“的提示。

        在任意客户端发送消息,服务器会接收到并将消息中转至其他客户端。

                                (两个不同客户端分别发送“abc123”和”你好“)

Read more

Flutter 三方库 wasm_ffi 深入鸿蒙端侧硬核 WebAssembly 虚拟机沙盒穿透适配全景:通过异步极速 FFI 中继管道打通底层高算力异构服务-适配鸿蒙 HarmonyOS ohos

Flutter 三方库 wasm_ffi 深入鸿蒙端侧硬核 WebAssembly 虚拟机沙盒穿透适配全景:通过异步极速 FFI 中继管道打通底层高算力异构服务-适配鸿蒙 HarmonyOS ohos

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 wasm_ffi 深入鸿蒙端侧硬核 WebAssembly 虚拟机沙盒穿透适配全景:通过异步极速 FFI 中继管道打通底层高算力异构服务并全面实现无损语言壁垒交互 前言 在 OpenHarmony 应用向高性能计算领域扩展的过程中,如何优雅地接入已有的 C/C++ 算法库(如加密引擎、重型图像处理、数学模拟)而又不失跨平台的便捷性?传统的 NAPI 虽然稳健,但在 Flutter 生态中,直接利用 WebAssembly (WASM) 配合 FFI(External Function Interface)的语义可以在一定程度上实现代码的高度复用。wasm_ffi 库为 Flutter 开发者提供了一套在 Dart 环境下调用 WASM

By Ne0inhk
三种适用于Web版IM(即时通讯)聊天信息的加密算法实现方案

三种适用于Web版IM(即时通讯)聊天信息的加密算法实现方案

文章目录 * **第一部分:引言与核心密码学概念** * **1.1 为什么IM需要端到端加密(E2EE)?** * **1.2 核心密码学概念与工具** * **第二部分:方案一:静态非对称加密(基础方案)** * **2.1 方案概述与流程** * **2.2 前端Vue实现(使用node-forge)** * **1. 安装依赖** * **2. 核心工具类 `crypto.js`** * **3. Vue组件中使用** * **2.3 后端Java实现(Spring Boot)** * **1. 实体类** * **2. Controller层** * **3. WebSocket配置** * **2.4 密钥管理、注册与登录集成** * **1. 用户注册/登录时生成密钥** * **2. 密钥设置页面** * **2.

By Ne0inhk
前端代码生成的大洗牌:当 GLM 4.7 与 MiniMax 挑战 Claude Opus,谁才是性价比之王?

前端代码生成的大洗牌:当 GLM 4.7 与 MiniMax 挑战 Claude Opus,谁才是性价比之王?

在 AI 辅助编程领域,长期以来似乎存在一条不成文的铁律:如果你想要最好的结果,就必须为最昂贵的模型买单(通常是 Anthropic 或 OpenAI 的旗舰模型)。然而,随着国产大模型如 GLM 4.7 和 MiniMax M2.1 的迭代,这一格局正在发生剧烈震荡。 最近,一场针对Claude Opus 4.5、Gemini 3 Pro、GLM 4.7 和 MiniMax M2.1 的前端 UI生成横向测评,打破了许多人的固有认知。在这场包含落地页、仪表盘、移动端应用等五个真实场景的较量中,不仅出现了令人咋舌的“滑铁卢”,更诞生了性价比极高的“新王”。 本文将深入拆解这场测试的细节,透过代码生成的表象,探讨大模型在工程化落地中的真实效能与成本逻辑。

By Ne0inhk
【Java Web学习 | 第14篇】JavaScript(8) -正则表达式

【Java Web学习 | 第14篇】JavaScript(8) -正则表达式

🌈个人主页: Hygge_Code🔥热门专栏:从0开始学习Java | Linux学习| 计算机网络💫个人格言: “既然选择了远方,便不顾风雨兼程” 文章目录 * JavaScript 正则表达式详解 * 什么是正则表达式🤔 * JavaScript 正则表达式的定义与使用🥝 * 1. 字面量语法 * 2. 常用匹配方法 * test() 方法🍋‍🟩 * exec() 方法🍋‍🟩 * 正则表达式的核心组成部分🐦‍🔥 * 1. 元字符 * 边界符 * 量词 * 字符类 * 2. 修饰符 * 简单示例🍂 JavaScript 正则表达式详解 正则表达式是处理字符串的强大工具,在 JavaScript 中被广泛应用于表单验证、文本处理和数据提取等场景。本文将从正则表达式的基本概念出发,详细介绍其语法规则和实际应用方法。 什么是正则表达式🤔 正则表达式是用于匹配字符串中字符组合的模式,在 JavaScript

By Ne0inhk