基于Java AIO 的数传服务器项目预研demo

本文详细介绍了一种基于AIO(异步I/O)的服务器与客户端实现方案,旨在提高数传服务器的报文处理能力。文章深入解析了AioServer和AioClient的代码实现,包括使用回调方式处理接收到的报文并进行加/解密,以及如何从控制台接收输入作为报文发送。此外,还提供了测试步骤,指导读者如何启动Server和Client进行实际测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目背景:

数传服务器项目,需对 与外界交互的 报文进行加/解密,提高数传服务器的报文处理能力;

因为数传服务器需随 便携设备 一起工作,所以并不能简单的依靠增加设备来提高的报文处理能力,因此项目改进点只能是提高单个设备的报文处理能力

目前数传服务器的 IO 已通过 NIO 实现,现自研以 AIO 的方式实现 Demo

相关说明:

数传服务器 属于 服务端功能,对接收到的报文进行 加/解密 后,再转发

目前数传服务器的 IO 已通过 NIO 实现,现自研以 AIO 的方式实现 Demo

demo说明:

  • AioServer :封装了 AIO 的 Server 实现,支持不间断的处理 接收到的报文,予以处理后再发送出去;(回调方式实现)
  • AioClient :封装了 AIO 的 Client 实现,支持从控制台接受输入作为报文,发送给客户端

NIO 的原理与基本概念,参考:

  • https://www.cnblogs.com/Theshy/p/7696313.html
  • https://blog.youkuaiyun.com/zmx729618/article/details/53171553

Demo实现

主要有两个类:

  • AioServer:封装了 AIO 的 Server 实现,支持不间断的处理 接收到的报文,予以处理后再发送出去;(回调方式实现)
  • AioClient :封装了 AIO 的 Client 实现,支持从控制台接受输入作为报文,发送给客户端

AioServer

封装了 AIO 的 Server 实现,支持不间断的处理 接收到的报文,予以处理后再发送出去;(回调方式实现)

package com.wj.io.aio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.*;
import java.util.function.Function;

/**
 * AIO 服务端,实现 不间断的 报文 收-处理-发 的过程
 */
public class AioServer implements Runnable {

    /**
     * 收发消息的编码格式
     */
    private final Charset utf8 = Charset.forName("UTF-8");
    /**
     * 服务端的处理逻辑(Function Interface)
     */
    private Function<String, String> service;
    /**
     * 服务端地址
     */
    private InetSocketAddress localAddress;
    /**
     * 异步 Channel 的分组管理器,它可以实现资源共享
     */
    private AsynchronousChannelGroup asynchronousChannelGroup = null;
    /**
     * AIO 服务端 Channel
     */
    private AsynchronousServerSocketChannel serverChannel = null;

    public AioServer(Function<String, String> service, int port) {
        this.service = service;
        this.localAddress = new InetSocketAddress(port);
    }

    public AioServer(Function<String, String> service, String hostname, int port) {
        this.service = service;
        this.localAddress = new InetSocketAddress(hostname, port);
    }

    @Override
    public void run() {

        try {

            init();

            serverChannel.accept(this, new CompletionHandler<AsynchronousSocketChannel, AioServer>() {

                @Override
                public void completed(AsynchronousSocketChannel socketChannel, AioServer aioServer) {
                    System.out.println("==============================================================");

                    System.out.println("server process begin...");

                    try {
                        System.out.println("client host: " + socketChannel.getRemoteAddress());

                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        socketChannel.read(buffer, buffer, new ReadCompletionHandler(socketChannel));

                    } catch (Exception e) {
                        /* TODO 结合具体业务逻辑处理... */
                    } finally {
                        // 监听新的connect,递归调用
                        aioServer.serverChannel.accept(aioServer, this);
                    }
                }

                @Override
                public void failed(Throwable e, AioServer attachment) {
                    /* TODO 结合具体业务逻辑处理... */
                }

            });

        } catch (Exception e) {
            /* TODO 结合具体业务逻辑处理... */
        }

    }

    private class ReadCompletionHandler implements CompletionHandler<Integer, ByteBuffer> {

        final AsynchronousSocketChannel socketChannel;

        public ReadCompletionHandler(AsynchronousSocketChannel socketChannel) {
            this.socketChannel = socketChannel;
        }

        @Override
        public void completed(Integer result, ByteBuffer buffer) {
            buffer.flip();
            System.out.println("received : " + utf8.decode(buffer));

            buffer.rewind();
            /* TODO service 服务处理 收到的 报文,并加以处理 */
            String rspMsg = service.apply(utf8.decode(buffer).toString());

            socketChannel.write(ByteBuffer.wrap(rspMsg.getBytes(StandardCharsets.UTF_8)));

            ByteBuffer buffer_ = ByteBuffer.allocate(1024);
            socketChannel.read(buffer_, buffer_, this);
        }

        @Override
        public void failed(Throwable exc, ByteBuffer buffer) {
            /* TODO 结合具体业务逻辑处理... */
        }
    }

    private void init() throws IOException {

        this.serverChannel = AsynchronousServerSocketChannel.open(asynchronousChannelGroup);

        serverChannel.bind(localAddress);

        System.out.println("listening on : " + localAddress.getHostString());
    }

    // -----------------------------------------------------------
    // setter / getter
    // -----------------------------------------------------------

    public void setAsynchronousChannelGroup(AsynchronousChannelGroup asynchronousChannelGroup) {
        this.asynchronousChannelGroup = asynchronousChannelGroup;
    }

    public static void main(String[] args) throws IOException {
        /* AsynchronousChannelGroup 可以理解为一个 JVM 中对于Socket相关操作的一些公共资源的代表  */
        AsynchronousChannelGroup asynchronousChannelGroup = AsynchronousChannelGroup.withCachedThreadPool(Executors.newCachedThreadPool(), 10);

        AioServer aioServer = new AioServer(msg -> "Msg Server send : " + msg, 8989);
        /* 系统中如果只有 一个 AioServer 服务端,此处可 set null,即不通过 AsynchronousChannelGroup 来新建 AsynchronousServerSocketChannel */
        aioServer.setAsynchronousChannelGroup(asynchronousChannelGroup);

        new Thread(aioServer).start();

        /* AIO 异步非阻塞,工作过程中不需要任何线程 监控,所以需要其他线程 保持工作状态,防止JVM关闭 */
        while (true) {

        }
    }
}

AioClient

封装了 AIO 的 Client 实现,支持从控制台接受输入作为报文,发送给客户端

package com.wj.io.aio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * AIO Client,可以从控制台输入报文,然后发送给 AIO Server
 */
public class AioClient implements Runnable {
    /**
     * AIO 客务端 Channel
     */
    private AsynchronousSocketChannel client;
    /**
     * 服务端地址
     */
    private InetSocketAddress remoteAddress;
    /**
     * 待发送数据的消息队列
     */
    private BlockingQueue<String> queue = new LinkedBlockingQueue<>();

    public AioClient(String host, int port) throws IOException {
        this.client = AsynchronousSocketChannel.open();
        this.remoteAddress = new InetSocketAddress(host, port);
    }

    public static void main(String[] args) throws IOException {
        AioClient client = new AioClient("127.0.0.1", 8989);
        new Thread(client).start();

        while (true) {
            // 模拟业务数据不断放入消息队列
            Scanner scanner = new Scanner(System.in);
            client.queue.add(scanner.nextLine());
        }
    }

    @Override
    public void run() {

        client.connect(remoteAddress, null, new CompletionHandler<Void, Object>() {

            @Override
            public void completed(Void result, Object attachment) {
                System.out.println("============== connect to server successfully. ================");

                try {
                    
                    /* 当消息队列中有元素,立即取出发送给 AIO Server */
                    while (true) {
                        String msg = queue.take();
                        client.write(ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8)));
                    }

                } catch (Exception e) {
                    /* TODO 结合具体业务逻辑处理... */
                }
            }

            @Override
            public void failed(Throwable exc, Object attachment) {
                /* TODO 结合具体业务逻辑处理... */
            }
        });

        final ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        client.read(byteBuffer, byteBuffer, new CompletionHandler<Integer, ByteBuffer>() {

            @Override
            public void completed(Integer result, ByteBuffer buffer) {
                System.out.println(result);
                System.out.println("client read data: " + new String(byteBuffer.array()));

                /* 监听新的消息,递归调用 */
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                client.read(byteBuffer, byteBuffer, this);
            }

            @Override
            public void failed(Throwable exc, ByteBuffer buffer) {
                /* TODO 结合具体业务逻辑处理... */
            }
        });
    }
}

测试时先起 Server 端,再起 Client 即可。

测试过程与结果

  1. 启动 Server 和 Client
  2. 在 Client 端控制台输入 报文

在这里插入图片描述
3. Server 端查看收到的消息
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值