JAVA异步的TCP 通讯-服务端

news2025/2/8 9:01:25

一、服务端代码示例

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class AdvancedAsyncTCPServer {
    private static final int PORT = 8888;
    private static final int BUFFER_SIZE = 1024;
    private final AsynchronousServerSocketChannel serverSocketChannel;
    private final ExecutorService threadPool;

    public AdvancedAsyncTCPServer() throws IOException {
        // 创建异步服务器套接字通道
        serverSocketChannel = AsynchronousServerSocketChannel.open();
        // 绑定到指定端口
        serverSocketChannel.bind(new InetSocketAddress(PORT));
        // 创建一个固定大小的线程池,用于处理业务逻辑
        threadPool = Executors.newFixedThreadPool(10);
        System.out.println("Server started on port " + PORT);
    }

    public void start() {
        // 开始接受客户端连接
        acceptConnections();
    }

    private void acceptConnections() {
        // 异步接受客户端连接
        serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
            @Override
            public void completed(AsynchronousSocketChannel clientChannel, Void attachment) {
                // 继续接受下一个连接
                acceptConnections();
                // 处理新连接
                handleConnection(clientChannel);
            }

            @Override
            public void failed(Throwable exc, Void attachment) {
                System.err.println("Failed to accept connection: " + exc.getMessage());
            }
        });
    }

    private void handleConnection(AsynchronousSocketChannel clientChannel) {
        // 创建缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
        // 异步读取客户端数据
        clientChannel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
            @Override
            public void completed(Integer bytesRead, ByteBuffer buffer) {
                if (bytesRead > 0) {
                    buffer.flip();
                    byte[] data = new byte[buffer.remaining()];
                    buffer.get(data);
                    String message = new String(data);
                    System.out.println("Received message from client: " + message);

                    // 使用线程池处理业务逻辑
                    threadPool.submit(() -> {
                        try {
                            // 模拟业务处理
                            String responseMessage = "Server processed: " + message;
                            ByteBuffer responseBuffer = ByteBuffer.wrap(responseMessage.getBytes());
                            // 异步发送响应给客户端
                            clientChannel.write(responseBuffer, responseBuffer, new CompletionHandler<Integer, ByteBuffer>() {
                                @Override
                                public void completed(Integer bytesWritten, ByteBuffer buffer) {
                                    System.out.println("Response sent to client");
                                    try {
                                        // 继续读取客户端数据
                                        buffer.clear();
                                        clientChannel.read(buffer, buffer, this);
                                    } catch (Exception e) {
                                        closeChannel(clientChannel);
                                    }
                                }

                                @Override
                                public void failed(Throwable exc, ByteBuffer buffer) {
                                    System.err.println("Failed to send response: " + exc.getMessage());
                                    closeChannel(clientChannel);
                                }
                            });
                        } catch (Exception e) {
                            closeChannel(clientChannel);
                        }
                    });
                } else if (bytesRead == -1) {
                    // 客户端关闭连接
                    closeChannel(clientChannel);
                } else {
                    // 继续读取客户端数据
                    buffer.clear();
                    clientChannel.read(buffer, buffer, this);
                }
            }

            @Override
            public void failed(Throwable exc, ByteBuffer buffer) {
                System.err.println("Failed to read data: " + exc.getMessage());
                closeChannel(clientChannel);
            }
        });
    }

    private void closeChannel(AsynchronousSocketChannel channel) {
        try {
            System.out.println("Closing client connection");
            channel.close();
        } catch (IOException e) {
            System.err.println("Error closing channel: " + e.getMessage());
        }
    }

    public void stop() {
        try {
            // 关闭服务器套接字通道
            serverSocketChannel.close();
            // 关闭线程池
            threadPool.shutdown();
        } catch (IOException e) {
            System.err.println("Error stopping server: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        try {
            AdvancedAsyncTCPServer server = new AdvancedAsyncTCPServer();
            server.start();
        } catch (IOException e) {
            System.err.println("Error starting server: " + e.getMessage());
        }
    }
}

二、代码分析

AdvancedAsyncTCPServer 类

  1. 构造函数:创建 AsynchronousServerSocketChannel 并绑定到指定端口,同时创建一个固定大小的线程池用于处理业务逻辑。

  2. start() 方法:开始接受客户端连接。
  3. acceptConnections() 方法:异步接受客户端连接,使用 CompletionHandler 处理连接结果。
  4. handleConnection() 方法:处理新连接,异步读取客户端数据,并使用线程池处理业务逻辑。
  5. closeChannel() 方法:关闭客户端通道。
  6. stop() 方法:关闭服务器套接字通道和线程池。

CompletionHandler

  1. 用于处理异步操作的完成结果,包括连接、读取和写入操作。
  2. 在 completed() 方法中处理成功的操作,在 failed() 方法中处理失败的操作。

线程池

  1. 使用 Executors.newFixedThreadPool(10) 创建一个固定大小的线程池,用于处理业务逻辑,避免阻塞 I/O 操作。

三、优点

  • 异步 I/O:使用 Java NIO 2 的异步 I/O 功能,提高了服务器的并发处理能力。
  • 线程池:使用线程池处理业务逻辑,避免了创建过多线程导致的性能问题。
  • 异常处理:对各种异常情况进行了处理,提高了代码的健壮性。
  • 资源管理:在关闭服务器时,正确关闭服务器套接字通道和线程池,避免资源泄漏。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2294707.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

零基础Vue入门6——Vue router

本节重点&#xff1a; 路由定义路由跳转 前面几节学习的都是单页面的功能&#xff08;都在专栏里面https://blog.csdn.net/zhanggongzichu/category_12883540.html&#xff09;&#xff0c;涉及到项目研发都是有很多页面的&#xff0c;这里就需要用到路由&#xff08;vue route…

关于JS继承的七种方式和理解

1.原型链继承 function Fun1() {this.name parentthis.play [1, 2, 3] } function Fun2() {this.type child }Fun2.prototype new Fun1()let s1 new Fun2() let s2 new Fun2() s1.play.push(4) console.log(s1.play, s2.play) // [1, 2, 3, 4] [1, 2, 3, 4]可以看到两个…

【Vue】在Vue3中使用Echarts的示例 两种方法

文章目录 方法一template渲染部分js部分方法一实现效果 方法二template部分js or ts部分方法二实现效果 贴个地址~ Apache ECharts官网地址 Apache ECharts示例地址 官网有的时候示例显示不出来&#xff0c;属于正常现象&#xff0c;多进几次就行 开始使用前&#xff0c;记得先…

每日Attention学习18——Grouped Attention Gate

模块出处 [ICLR 25 Submission] [link] UltraLightUNet: Rethinking U-shaped Network with Multi-kernel Lightweight Convolutions for Medical Image Segmentation 模块名称 Grouped Attention Gate (GAG) 模块作用 轻量特征融合 模块结构 模块特点 特征融合前使用Group…

124,【8】buuctf web [极客大挑战 2019] Http

进入靶场 查看源码 点击 与url有关&#xff0c;抓包 over

源路由 | 源路由网桥 / 生成树网桥

注&#xff1a;本文为 “源路由” 相关文章合辑。 未整理去重。 什么是源路由&#xff08;source routing&#xff09;&#xff1f; yzx99 于 2021-02-23 09:45:51 发布 考虑到一个网络节点 A 从路由器 R1 出发&#xff0c;可以经过两台路由器 R2、R3&#xff0c;到达相同的…

FPGA的IP核接口引脚含义-快解

疑问 手册繁琐&#xff0c;怎样快速了解IP核各输入输出接口引脚的含义。 答疑 不慌不慌&#xff0c;手册确实比较详细但繁琐&#xff0c;如何快速知晓该部分信息&#xff0c;涛tao道长给你们说&#xff0c;简单得很&#xff0c;一般新入门的道友有所不知&#xff0c;往往后面…

Qwen2-VL-2B-Instruct 模型 RK3576 板端部署过程

需要先在电脑上运行 RKLLM-Toolkit 工具&#xff0c;将训练好的模型转换为 RKLLM 格式的模型&#xff0c;然后使用 RKLLM C API 在开发板上进行推理。 在安装前先查看板端的内存容量&#xff0c;和自己模型占用大小比较一下&#xff0c;别安装编译好了不能用。 这里我就是先尝试…

如何设计光耦电路

光耦长这样&#xff0c;相信小伙伴们都见过&#xff0c;下图是最为常用的型号PC817 怎么用&#xff1f;我们先看图&#xff0c;如下图1&#xff1a; Vin为输入信号&#xff0c;一般接MCU的GPIO口&#xff0c;由于这里的VCC1为3.3V&#xff0c;故MCU这边的供电电源不能超过3.3V…

ADC模数转换器概念函数及应用

ADC模数转换器概念函数及应用 文章目录 ADC模数转换器概念函数及应用1.ADC简介2.逐次逼近型ADC2.1逐次逼近型ADC2.2stm32逐次逼近型2.3ADC基本结构2.4十六个通道 3.规则组的4种转换模式3.1单次转换&#xff0c;非扫描模式3.2连续转换&#xff0c;非扫描模式3.3单次转换&#xf…

DFX(Design for eXcellence)架构设计全解析:理论、实战、案例与面试指南*

一、什么是 DFX &#xff1f;为什么重要&#xff1f; DFX&#xff08;Design for eXcellence&#xff0c;卓越设计&#xff09;是一种面向产品全生命周期的设计理念&#xff0c;旨在确保产品在设计阶段就具备**良好的制造性&#xff08;DFM&#xff09;、可测试性&#xff08;…

【LeetCode】152、乘积最大子数组

【LeetCode】152、乘积最大子数组 文章目录 一、dp1.1 dp1.2 简化代码 二、多语言解法 一、dp 1.1 dp 从前向后遍历, 当遍历到 nums[i] 时, 有如下三种情况 能得到最大值: 只使用 nums[i], 例如 [0.1, 0.3, 0.2, 100] 则 [100] 是最大值使用 max(nums[0…i-1]) * nums[i], 例…

《云夹:让书签管理变得轻松又高效》

在当今数字化的生活与工作场景中&#xff0c;我们畅游于网络的浩瀚海洋&#xff0c;每天都会邂逅各式各样有价值的网页内容。而如何妥善管理这些如繁星般的书签&#xff0c;使其能在我们需要时迅速被找到&#xff0c;已然成为众多网络使用者关注的焦点。云夹&#xff0c;作为一…

Microsoft Fabric - 尝试一下在pipeline中发送请求给web api(获取数据和更新数据)

1.简单介绍 Microsoft Fabric中的Pipeline支持很多种activity&#xff0c;分成数据转换和控制流两种类型的activitly。 这边将尝试一下发送web请求的activity&#xff0c;要做成的pipeline大概如下图所示&#xff0c; 上图中有4个Activity&#xff0c;作用如下 Web - 从一个…

数据完整性与约束的分类

一、引言 为什么需要约束&#xff1f;为了保证数据的完整性。 &#xff08;1&#xff09;数据完整性 数据完整性指的是数据的精确性和可靠性。 为了保证数据的完整性&#xff0c;SQL对表数据进行额外的条件限制&#xff0c;从以下四方面考虑&#xff1a; ①实体完整性&…

docker安装nacos2.x

本文为单机模式&#xff0c;非集群教程&#xff0c;埋坑 nacos2.x官方强制条件 64 bit OS&#xff0c;支持 Linux/Unix/Mac/Windows&#xff0c;推荐选用 Linux/Unix/Mac。 64 bit JDK 1.8 Maven 3.2.x 环境介绍 centos 7 maven 3.9.9 jdk 17 nacos 2.3.1 1. 拉取docker镜像 d…

GB/T28181 开源日记[8]:国标开发速知速会

服务端源代码 github.com/gowvp/gb28181 前端源代码 github.com/gowvp/gb28181_web 介绍 go wvp 是 Go 语言实现的开源 GB28181 解决方案&#xff0c;基于GB28181-2022标准实现的网络视频平台&#xff0c;支持 rtmp/rtsp&#xff0c;客户端支持网页版本和安卓 App。支持rts…

6 maven工具的使用、maven项目中使用日志

文章目录 前言一、maven&#xff1a;一款管理和构建java项目的工具1 基本概念2 maven的安装与配置&#xff08;1&#xff09;maven的安装&#xff08;2&#xff09;IDEA集成Maven配置当前项目工程设置 maven全局设置 &#xff08;3&#xff09;创建一个maven项目 3 pom.xml文件…

GB/T 43698-2024 《网络安全技术 软件供应链安全要求》标准解读

一、43698-2024标准图解 https://mmbiz.qpic.cn/sz_mmbiz_png/rwcfRwCticvgeBPR8TWIPywUP8nGp4IMFwwrxAHMZ9Enfp3wibNxnfichT5zs7rh2FxTZWMxz0je9TZSqQ0lNZ7lQ/640?wx_fmtpng&fromappmsg 标准在线预览&#xff1a; 国家标准|GB/T 43698-2024 相关标准&#xff1a; &a…

CF 278A.Circle Line

题目分析 输入n个数据作为路径&#xff0c;求从a到b的最短距离&#xff0c;需要将其相成一个圆圈&#xff0c;既可以从小往大走又可以从大往小走 思路分析 依然将数据存为数组&#xff0c;通过下标进行操作&#xff0c;既然说了有两种方式那就计算两种方式哪个更快就输出谁 代…