跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Java 网络通信实战:Socket 编程与 MINA 框架上手

从基础的 Socket 通信出发,演示了 Java 中 TCP、UDP 和 URL 的网络编程方法,并逐步构建了多客户端并发处理和消息转发模型,最后引入 MINA 框架简化 NIO 开发。

CodeArtist发布于 2026/6/30更新于 2026/8/2219 浏览

网络编程里,TCP 和 UDP 是绕不开的两个传输协议。TCP 保证可靠送达,三次握手之后建立连接,再通过流式传输收发数据;UDP 则是无连接的数据报方式,发出去就不管了,适合实时性要求高但对丢包不敏感的场景。

日常开发中接触更多的是 TCP,尤其是基于 Socket 的编程模型。Java 把底层的细节封装得还算干净,ServerSocket 和 Socket 两个类就能搭起最简单的客户端/服务端通信。写起来不复杂,但有几个点踩过坑之后印象会比较深:

  • server.accept() 是阻塞的,没等到客户端连接就不会往下走。
  • BufferedReader.readLine() 读不到数据也会卡住,所以协议里最好约定好结束符或固定长度,不然两边都可能死等。
  • 带缓冲的输出流记得 flush(),否则数据可能一直留在本地缓冲区没发出去。

一个最简的回显(Echo)服务器大概是这样:

// 服务端
ServerSocket server = new ServerSocket(6666);
Socket socket = server.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String info = br.readLine();
PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
ps.println("echo: " + info);
ps.flush();
ps.close();
br.close();

客户端连上后发一句话,再读回服务器拼接的 "echo: ..."。这种做法简单直接,适合用来理解通信流程,但真正工程里很少这样用:单连接、单线程,多个客户端同时过来就处理不了。

处理多个客户端:线程池 + 每连接一线程

要同时应付多个客户端,经典的做法是主线程只负责 accept,每拿到一个新的 Socket 就交给线程池去处理。这里用 Executors.newFixedThreadPool 限制并发线程数,避免资源耗尽。

ServerSocket server = new ServerSocket(6666);
ExecutorService es = Executors.newFixedThreadPool(3);
while (true) {
    Socket socket = server.accept();
    System.out.println("连接来自:" + socket.getInetAddress().getHostAddress());
    es.execute(new ClientHandler(socket));
}

ClientHandler 的 run 方法里就是针对这一个 socket 的读写逻辑:读一行、处理、写回、关闭流。这里没有做复杂的心跳和异常处理,真实环境还得考虑半关闭、断线重连等细节。

客户端之间的消息转发

如果想让客户端 A 给客户端 B 发消息,就需要服务器做中转。做法是让每个连接在服务端有一个对应的处理线程,并为每个用户起一个唯一的名字(比如登录时指定的用户名)。服务端维护一个集合,存着所有在线用户的处理线程引用。

A 发送消息时,先发给服务器,服务器根据目标名字从集合里找到 B 对应的处理线程,再由那个线程将消息写回 B 的 socket。这个过程中,消息得带上源用户、目标用户、消息体和消息类型,所以定义一个可序列化的 Message 类就很方便。

public class Message implements Serializable {
    private String from;
    private String to;
    private String info;
    private int type;
    // 构造器、getter/setter 略
}

服务器在读取到客户端发来的 Message 后,根据 type 区分登录消息和普通转发消息。登录时,服务端将当前客户端的名称记录下来,并回复欢迎信息。转发时,遍历集合找到目标线程,把消息写过去。

客户端一边在主线程等待用户输入并发送,一边开一条子线程专门读取服务器转发来的消息,这样才不会漏掉别人发来的内容。

用 Vector<ClientThread> 存线程引用,其实多线程下最好用并发安全的集合,比如 CopyOnWriteArrayList,但这里只是 Demo 用途,暂未深究。

UDP:无连接的数据报

UDP 的代码结构很不一样。接收端和发送端各自创建 DatagramSocket,收数据用的是 DatagramPacket 包裹一个字节数组缓冲区,socket.receive(packet) 会阻塞直到收到数据报。发数据则要指定目标的 InetAddress 和端口。

一个很容易忘的细节:UDP 要先启动接收方,否则发送的数据就丢了——毕竟 UDP 不缓存,发了拉倒。所以哪怕你代码里叫 UDPClient 是接收方,也得让它先跑起来。

// 接收端(Client)
DatagramSocket socket = new DatagramSocket(8000);
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
socket.receive(dp);
String info = new String(dp.getData(), 0, dp.getLength());
// 发送端(Server)
DatagramSocket ds = new DatagramSocket(9000);
String s = "good good study, 天天 up";
DatagramPacket dp = new DatagramPacket(
    s.getBytes(), 0, s.getBytes().length,
    InetAddress.getByName("localhost"), 8000
);
ds.send(dp);

数据报最大 64KB,所以适合发送短消息、实时视频音频流这类控制没那么严格的场合。

用 URL 下载文件

Java 里通过 URL 对象可以方便地拿到网络资源流,再用 HttpURLConnection 进行一些配置。下面这段代码直接从一个美团图片地址下载图片到本地,算是最基础的网络资源抓取。

URL url = new URL("https://p1.meituan.net/biztone/1730f0baefe95984e632a52590f0b446393917.jpg");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("/Users/mac/D/hello.png"));
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) != -1) {
    bos.write(bytes, 0, len);
}
bis.close();
bos.close();

这里有两点注意:路径要写对文件系统里有权限的位置,另外生产环境还得处理响应码和超时。

MINA 框架:让 NIO 写起来更顺手

原生的 NIO 编程复杂度不低,MINA 框架做了一层封装,用起来思路很清晰:创建 Acceptor/Connector,配置过滤器链,再提供一个 Handler 处理事件。

服务端启动代码:

NioSocketAcceptor acceptor = new NioSocketAcceptor();
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
chain.addLast("myChain", new ProtocolCodecFilter(new TextLineCodecFactory()));
acceptor.setHandler(new MinaServerHandler());
acceptor.bind(new InetSocketAddress(9999));

TextLineCodecFactory 帮我们做了粘包拆包,省了不少心。如果需要传输自定义对象,换一个 new ProtocolCodecFilter(new ObjectSerializationCodecFactory()) 就好。

Handler 继承 IoHandlerAdapter,复写几个关键方法:

public class MinaServerHandler extends IoHandlerAdapter {
    public void sessionOpened(IoSession session) {
        System.out.println("新连接:" + session.getRemoteAddress());
    }
    public void messageReceived(IoSession session, Object message) {
        String msg = (String) message;
        session.write("echo:" + msg);
    }
    public void sessionClosed(IoSession session) {
        System.out.println("连接断开");
    }
}

客户端也类似,创建 NioSocketConnector 并连接,connectFuture.awaitUninterruptibly() 确保连上再继续。主线程循环读用户输入直接 write 给服务端,收到消息的回显则会在自定义 Handler 里打印。

整个 MINA 部分代码量不多,但已经能跑起来。想深入的话,可以继续研究 IoBuffer、编解码器链、以及如何处理大量长连接。

这些 Demo 覆盖了 Java 网络编程里最常用的几个模式:阻塞 Socket、多线程处理、中转转发、UDP 通信、URL 资源读取、以及基于 MINA 的 NIO 通讯。它们都不完美,但作为理解底层原理和快速上手的基础足够了。实际项目里还得根据需求加上心跳、连接池、超时控制和健壮的异常处理。

目录

  1. 处理多个客户端:线程池 + 每连接一线程
  2. 客户端之间的消息转发
  3. UDP:无连接的数据报
  4. 用 URL 下载文件
  5. MINA 框架:让 NIO 写起来更顺手
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • AI 大模型从入门到精通学习指南
  • Windows 本地部署闲鱼 AI 自动回复系统实战指南
  • 金仓 KingbaseES 融合架构实践:从多库并存到一库多能
  • Stable Diffusion 新手入门:AI 绘画基础与指令详解
  • OpenClaw 接入飞书机器人与 Kimi2.5 配置指南
  • 快速排序非递归实现详解
  • SQL Server 2019 下载安装及配置教程
  • 基于 Rust 从零开发隐写工具
  • GitHub 爆火的“蒸馏 Skill”:用聊天记录复刻数字分身,是赛博永生还是隐私风险?
  • Coze 智能体开发:插件、知识库与数据库全解析
  • RoboMME:机器人通用策略的记忆基准测试与理解
  • C++ 实现 JSON 与 HTTP 协议,从零构建 Web 计算器服务器
  • AI 写作辅助平台推荐:炼字工坊与蛙蛙写作
  • MAVROS 安装与基础指南:ROS C++ 无人机仿真实战
  • 基于 LLaMA-Factory 的 Qwen3.5-4B 医疗助手微调指南
  • WebSite-Downloader 网站整站下载工具使用指南
  • Spring Web MVC 入门指南:从概念到实践
  • 大模型全解:定义、原理、应用与优劣势分析
  • Claude Code 核心执行模式详解:权限、计划与自动编辑
  • 基于 YOLOv5 的深度学习火焰检测与识别系统

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online