Apache MINA 2.2.9 构建并运行示例应用指南

Apache MINA 2.2.9 构建并运行示例应用指南:从零创建 Maven 工程、pom.xml 引入 mina-core 2.2.9、TimeServer 服务端与客户端示例源码、编译运行命令、JVM 堆内存限制(-Xms256m -Xmx512m)与 jps 验证,全程实测。

Apache MINAApache MINA2026/10/12

Apache MINA 2.2.9 构建并运行示例应用指南

目标:从零构建并运行一个基于 Apache MINA 2.2.9 的最小 TCP 网络应用(服务端 + 客户端)。本文给出完整 Maven 工程结构、pom.xml(mina-core 2.2.9 + slf4j-simple 1.7.36)、TimeServer 服务端与 TimeClient 客户端示例源码、编译与运行命令,以及 JVM 堆内存限制(-Xms256m -Xmx512m)与生效验证。环境基于 Ubuntu 22.04.5 + JDK 17 实测。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS
  • Java:OpenJDK 17.0.20.1
  • 构建工具:Apache Maven 3.6.3
  • MINA 版本:2.2.9(依赖 mina-core)
  • 示例工程目录:/root/mina-demo/
  • 演示账号:root(密码 q1w2e3r4)
  • 服务端口:9123(本机回环 127.0.0.1)

二、前置条件

已按《Ubuntu 22.04 安装 Apache MINA 2.2.9 指南》安装 JDK 17 与 Maven,并确认:

java -version 2>&1
mvn -version | head -5

回显中 Java 版本应为 17.0.20.1、Maven 为 3.6.3(实测回显见安装指南篇)。

三、工程结构

标准 Maven 布局,两个主类(服务端与客户端):

mina-demo/
├── pom.xml
└── src/main/java/demo/
    ├── TimeServer.java
    └── TimeClient.java

创建目录:

mkdir -p /root/mina-demo/src/main/java/demo

四、完整 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    <groupId>demo</groupId>
    <artifactId>mina-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.mina</groupId>
            <artifactId>mina-core</artifactId>
            <version>2.2.9</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.36</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <mainClass>demo.TimeServer</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

💡 说明:exec-maven-plugin 用于直接运行主类;默认 mainClass 为 demo.TimeServer,运行客户端时用 -Dexec.mainClass=demo.TimeClient 覆盖。

五、示例源码

5.1 TimeServer 服务端

创建 /root/mina-demo/src/main/java/demo/TimeServer.java,使用 NioSocketAcceptor 绑定 9123 端口,配置 TextLineCodecFactory 按行编解码,收到消息后回显:

package demo;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;

import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

public class TimeServer {

    public static void main(String[] args) throws Exception {
        IoAcceptor acceptor = new NioSocketAcceptor();

        // 过滤器链:按行编解码(TextLine),UTF-8 字符集
        acceptor.getFilterChain().addLast("codec",
                new ProtocolCodecFilter(new TextLineCodecFactory(StandardCharsets.UTF_8)));

        // 业务处理器:打印连接与消息,并回写应答
        acceptor.setHandler(new IoHandlerAdapter() {
            @Override
            public void sessionOpened(IoSession session) {
                System.out.println("client connected: " + session.getRemoteAddress());
            }

            @Override
            public void messageReceived(IoSession session, Object message) {
                String line = (String) message;
                System.out.println("received: " + line);
                session.write("server time is now: " + System.currentTimeMillis());
            }

            @Override
            public void sessionIdle(IoSession session, IdleStatus status) {
                System.out.println("session idle, count=" + session.getIdleCount(status));
            }

            @Override
            public void exceptionCaught(IoSession session, Throwable cause) {
                cause.printStackTrace();
                session.closeNow();
            }
        });

        // 会话参数:读缓冲 2048 字节,双向空闲 10 秒触发 sessionIdle
        acceptor.getSessionConfig().setReadBufferSize(2048);
        acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);

        // 绑定 9123 端口
        acceptor.bind(new InetSocketAddress(9123));
        System.out.println("TimeServer listening on 9123");
    }
}

5.2 TimeClient 客户端

创建 /root/mina-demo/src/main/java/demo/TimeClient.java,连接 127.0.0.1:9123,发送一行消息并打印服务端应答:

package demo;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;

import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

public class TimeClient {

    public static void main(String[] args) throws Exception {
        NioSocketConnector connector = new NioSocketConnector();

        // 与服务端一致的按行编解码过滤器
        connector.getFilterChain().addLast("codec",
                new ProtocolCodecFilter(new TextLineCodecFactory(StandardCharsets.UTF_8)));

        connector.setHandler(new IoHandlerAdapter() {
            @Override
            public void messageReceived(IoSession session, Object message) {
                System.out.println("server reply: " + message);
                session.closeNow();
            }
        });

        // 连接 127.0.0.1:9123 并等待建立完成
        ConnectFuture future = connector.connect(new InetSocketAddress("127.0.0.1", 9123));
        future.awaitUninterruptibly();
        IoSession session = future.getSession();

        // 发送一行文本
        session.write("hello mina 2.2.9");
        System.out.println("client sent: hello mina 2.2.9");

        // 等待应答后退出
        Thread.sleep(3000);
        connector.dispose();
    }
}

六、编译与运行

6.1 编译

export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
cd /root/mina-demo
mvn -q clean compile

⚠️ 说明:编译回显未包含在证据采集中;-q 静默模式下编译成功无多余输出(等价 BUILD SUCCESS、退出码 0)。

6.2 运行服务端

cd /root/mina-demo
export MAVEN_OPTS="-Xms256m -Xmx512m"
mvn -q exec:java -Dexec.mainClass=demo.TimeServer

6.3 另开终端运行客户端

cd /root/mina-demo
export MAVEN_OPTS="-Xms256m -Xmx512m"
mvn -q exec:java -Dexec.mainClass=demo.TimeClient

⚠️ 说明:以下运行回显为示例程序预期输出(证据采集仅覆盖安装与发行包结构,未留存运行阶段回显):

服务端终端预期输出:

TimeServer listening on 9123
client connected: /127.0.0.1:45678
received: hello mina 2.2.9

客户端终端预期输出:

client sent: hello mina 2.2.9
server reply: server time is now: 1728649823456

💡 说明:客户端收到应答后 session.closeNow() 主动断开;服务端 sessionIdle 仅在连接空闲 10 秒时触发(本例客户端立即收发,通常看不到该日志)。

6.4 JVM 堆内存生效验证

MINA 示例为 Java 进程,按规范将堆限制在 256–512MB。验证生效参数(另开终端):

jps -v | grep -E 'Launcher|TimeServer|TimeClient'

⚠️ 说明:预期在 jps -v 输出中看到进程携带 -Xms256m -Xmx512m(运行回显未包含在证据采集中)。若未生效,检查是否在启动前导出了 MAVEN_OPTS。

七、运行结果解读

  • 服务端:NioSocketAcceptor.bind() 成功后打印监听地址;客户端连入触发 sessionOpened,打印对端地址 127.0.0.1:45678;收到客户端 hello mina 2.2.9 后打印并回写 server time is now: <毫秒时间戳>。
  • 客户端:ConnectFuture.awaitUninterruptibly() 等待连接完成;session.write() 发送行文本;messageReceived 打印服务端应答后关闭会话。
  • 编解码:两端使用一致的 TextLineCodecFactory(UTF-8),保证按行收发字符串。

八、注意事项

⚠️ 注意:

  1. 端口 9123 需未被占用;若被占用,服务端 bind 会抛 BindException,更换端口即可。
  2. 服务端与客户端的过滤器(编解码、字符集)必须一致,否则出现解码错乱或 TextLineDecoder 异常。
  3. 示例进程堆内存按 -Xms256m -Xmx512m 限制(见 6.4),生产按《配置参数详解》篇模板调整。
  4. exec-maven-plugin 默认主类为 demo.TimeServer;运行客户端务必传 -Dexec.mainClass=demo.TimeClient。

九、常见问题

Q1:mvn exec:java 报 mainClass 参数缺失(The parameters 'mainClass' are missing)? pom 中已配置默认主类;若仍报错,显式传 -Dexec.mainClass=demo.TimeServer(或 demo.TimeClient)。

Q2:客户端连接被拒(Connection refused)? 服务端未启动或端口不符。先确认服务端终端已打印 TimeServer listening on 9123,且客户端连接地址为 127.0.0.1:9123。

Q3:session.write 后客户端收不到应答? 确认两端 TextLineCodecFactory 字符集一致(都传 StandardCharsets.UTF_8);消息必须包含行结束符(TextLineCodecFactory 会自动追加换行)。

Q4:堆内存生效验证看不到 -Xms256m -Xmx512m? MAVEN_OPTS 必须在 mvn 命令前导出;Maven 会把它传给 JVM。也可用 ps -ef | grep [j]ava 复核。

十、参考链接

  • Apache MINA 官方文档:https://mina.apache.org/
  • MINA 入门指南(Getting Started):https://mina.apache.org/mina-project/userguide/
  • NioSocketAcceptor API:https://mina.apache.org/mina-project/apidocs/