当前位置: 首页 > article >正文

IO、NIO、Netty实战

目标客户端和服务端互相通信本文主要是实战练习照着敲然后debug看为什么就行前置理解模型核心类特点简述BIOServerSocket / Socket一个连接一个线程accept()和read()都会阻塞简单但连接多了线程爆炸NIOSelector / ServerSocketChannel / SocketChannel / ByteBuffer一个 Selector 管理多个 Channel非阻塞轮询复杂但一个线程扛几百连接NettyServerBootstrap / EventLoopGroup / Pipeline / Handler封装了 NIO 的复杂性用责任链处理数据高性能框架写业务逻辑就行练习递进关系BIO 理解通信本质 → NIO 理解多路复用 → Netty 理解工程化封装。三种服务端可以混搭客户端底层都是 TCP 协议BIO 客户端可以连 NIO 服务端反之亦然。IO服务端publicclassIOServer{privatestaticfinalThreadPoolExecutorclientPoolnewThreadPoolExecutor(2,//最小线程数3,//最大线程数60L,//线程空闲时间TimeUnit.SECONDS,// 时间单位newArrayBlockingQueue(1),// 任务队列容量newThreadPoolExecutor.CallerRunsPolicy()// 拒绝策略);publicstaticvoidmain(String[]args)throwsIOException{//IO服务端ServerSocketserverSocketnewServerSocket(8888);while(true){// 添加线程池状态监控System.out.println(当前线程池状态 - 活跃线程: clientPool.getActiveCount(), 队列大小: clientPool.getQueue().size());SocketclientSocketserverSocket.accept();System.out.println(客户端连接: clientSocket.getInetAddress());// new Thread(()-handleClient(clientSocket)).start();try{// 提交任务clientPool.execute(()-handleClient(clientSocket));System.out.println(✅ 任务已提交);}catch(Exceptione){System.err.println(❌ 提交失败);clientSocket.close();}}}privatestaticvoidhandleClient(SocketclientSocket){try{clientSocket.setSoTimeout(60000);}catch(SocketExceptione){return;}//inpustStream获取输入流//outputStream获取输出流//InputStreamReader将输入流转换为字符流//BufferedReader将字符流转换为缓冲流try(InputStreaminputStreamclientSocket.getInputStream();BufferedReaderreadernewBufferedReader(newInputStreamReader(inputStream));){Stringline;while((linereader.readLine())!null){System.out.printf(Thread.currentThread().getName()收到客户端消息:line\n);}System.out.println(客户端已断开);}catch(SocketTimeoutExceptione){System.out.println(客户端空闲超时主动踢下线);}catch(IOExceptione){e.printStackTrace();}finally{try{clientSocket.close();// 只关客户端不关服务端System.out.println(资源已清理线程退出);}catch(IOExceptione){e.printStackTrace();}}}}客户端publicclassIOClient{publicstaticvoidmain(String[]args)throwsIOException{//IO客户端SocketsocketnewSocket(127.0.0.1,8888);OutputStreamossocket.getOutputStream();ScannerscnewScanner(System.in);while(sc.hasNext()){Stringmsgsc.nextLine();if(exit.equalsIgnoreCase(msg)){socket.shutdownOutput();// 关闭输出流通知服务端读完了break;}os.write((msg\n).getBytes());os.flush();}os.close();socket.close();}}NIO服务端publicclassNIOServer{publicstaticfinalThreadPoolExecutortpnewThreadPoolExecutor(2,10,60L,TimeUnit.SECONDS,newArrayBlockingQueue(1),newThreadPoolExecutor.CallerRunsPolicy());privateNIOServerstart()throwsIOException{//配置nio管理员SelectorselectorSelector.open();ServerSocketChannelserverSocketChannelServerSocketChannel.open();serverSocketChannel.bind(newInetSocketAddress(8888));serverSocketChannel.configureBlocking(false);//取消阻塞// 注册serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);while(true){selector.select();SetSelectionKeyselectionKeysselector.selectedKeys();//获取迭代器IteratorSelectionKeyiteratorselectionKeys.iterator();while(iterator.hasNext()){SelectionKeykeyiterator.next();iterator.remove();// 处理不同事件if(key.isAcceptable()){handleAccept(key);// 新客户端连接}elseif(key.isReadable()){handleRead(key);// 客户端发消息}}}}publicstaticvoidmain(String[]args)throwsIOException{newNIOServer().start();}privatestaticvoidhandleAccept(SelectionKeykey)throwsIOException{ServerSocketChannelserver(ServerSocketChannel)key.channel();SocketChannelchannelserver.accept();channel.configureBlocking(false);channel.register(key.selector(),SelectionKey.OP_READ,ByteBuffer.allocate(1024));System.out.println(\n新客户端连接channel.getRemoteAddress());}privatestaticvoidhandleRead(SelectionKeykey){SocketChannelclient(SocketChannel)key.channel();ByteBufferbuffer(ByteBuffer)key.attachment();try{intlenclient.read(buffer);// 非阻塞读取if(len-1){// 客户端断开System.out.println(客户端断开client.getRemoteAddress());client.close();key.cancel();return;}// 切换读模式buffer.flip();StringmsgnewString(buffer.array(),0,len);buffer.clear();System.out.println(收到消息msg);tp.execute(()-{System.out.println(Thread.currentThread().getName() 执行业务 → msg);});}catch(IOExceptione){// 强制断开try{client.close();key.cancel();}catch(IOExceptionex){ex.printStackTrace();}}}}客户端publicclassNIOClient{publicstaticvoidmain(String[]args)throwsIOException{// 1. 打开客户端通道SocketChannelclientSocketChannel.open(newInetSocketAddress(127.0.0.1,8888));client.configureBlocking(false);// 非阻塞模式ScannerscnewScanner(System.in);ByteBufferbufferByteBuffer.allocate(1024);while(sc.hasNext()){Stringmsgsc.nextLine();if(exit.equalsIgnoreCase(msg)){break;}// 写数据到服务端buffer.clear();buffer.put((msg\n).getBytes());buffer.flip();client.write(buffer);}client.close();}}Netty客户端public class NettyClient { private Channel channel; public final EventLoopGroup group new NioEventLoopGroup(); public static void main(String[] args) throws InterruptedException { NettyClient client new NettyClient(); new Thread(()-{ try { client.start(127.0.0.1,8888); } catch (InterruptedException e) { throw new RuntimeException(e); } }).start(); Scanner sc new Scanner(System.in); while (sc.hasNext()){ String msg sc.nextLine(); if(exit.equalsIgnoreCase(msg)) { client.sendMsg(拜拜); client.close(); break; } client.sendMsg(msg); } } public void start(String host,Integer port) throws InterruptedException { Bootstrap bootstrap new Bootstrap(); bootstrap .group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializerSocketChannel() { Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline() // .addLast(new LoggingHandler(LogLevel.INFO)) // 拆包参数和服务端一模一样 .addLast(new LengthFieldBasedFrameDecoder(1024 * 1024, 0, 4, 0, 4)) .addLast(new LengthFieldPrepender(4)) .addLast(new StringDecoder()) .addLast(new StringEncoder()) // 客户端心跳 .addLast(new IdleStateHandler(30, 60, 120)) // 客户端自定义业务处理器 .addLast(new MyClientHandler()); } }); ChannelFuture future bootstrap.connect(host, port).sync(); this.channel future.channel(); future.channel().closeFuture().sync(); } public void sendMsg(String msg) { if (channel ! null channel.isActive()) { channel.writeAndFlush(msg); } else { System.out.println(连接未成功无法发送); } } public void close() { if (channel ! null) channel.close(); group.shutdownGracefully(); } }方法配置public class MyClientHandler extends SimpleChannelInboundHandlerString { Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { System.out.println(客户端收到服务端消息 msg); } // 连接成功建立 Override public void channelActive(ChannelHandlerContext ctx) { System.out.println(客户端成功连接服务端); // 连接成功主动发一条消息 ctx.writeAndFlush(客户端上线啦); } // 连接断开 Override public void channelInactive(ChannelHandlerContext ctx) { System.out.println(客户端与服务端连接断开); } // 心跳事件处理 Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { // 判断是不是空闲事件 if (evt instanceof IdleStateEvent) { IdleStateEvent event (IdleStateEvent) evt; // 如果是【写空闲】 30秒没发消息 if (event.state() IdleState.WRITER_IDLE) { // 自动发一个心跳包 ctx.writeAndFlush(heartbeat); } } } }服务端public class NettyServer { private static final EventLoopGroup boss new NioEventLoopGroup(1); private static final EventLoopGroup worker new NioEventLoopGroup(); public void start(int port) throws InterruptedException { try { ServerBootstrap bootstrap new ServerBootstrap(); bootstrap .group(boss, worker) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializerSocketChannel() { Override protected void initChannel(SocketChannel ch) throws Exception { //输入输出 ChannelPipeline pipeline ch.pipeline(); // pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //日志打印 pipeline.addLast(new LengthFieldBasedFrameDecoder(1024 * 1024, 0, 4, 0, 4)); pipeline.addLast(new LengthFieldPrepender(4)); pipeline.addLast(new StringDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new IdleStateHandler(60, 30, 120)); pipeline.addLast(new MyServerHandler()); } }); //绑定端口 同步阻塞 ChannelFuture channelFuture bootstrap.bind(port).sync(); //等待服务关闭通道 channelFuture.channel().closeFuture().sync(); }catch(Exception e){ e.printStackTrace(); }finally { boss.shutdownGracefully(); worker.shutdownGracefully(); } } public static void main(String[] args) throws InterruptedException { // 启动服务端 new NettyServer().start(8888); } }方法配置public class MyServerHandler extends SimpleChannelInboundHandlerString { //全局用户集合concurrentHashMap public static final SetString ONLINE_CLIENTS ConcurrentHashMap.newKeySet(); private static final ThreadPoolExecutor tp new ThreadPoolExecutor(5, 10, 60L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(1),new ThreadPoolExecutor.AbortPolicy()); Override public void channelActive(ChannelHandlerContext ctx) { SocketAddress socketAddress ctx.channel().remoteAddress(); tp.execute(() - { ONLINE_CLIENTS.add(socketAddress.toString()); System.out.println(有新客户端连接 ctx.channel().remoteAddress()); System.out.println(当前人数ONLINE_CLIENTS.size()); ctx.writeAndFlush(欢迎连接); ctx.writeAndFlush(当前人数ONLINE_CLIENTS.size()); }); } Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); } Override public void channelInactive(ChannelHandlerContext ctx) { String clientAddr ctx.channel().remoteAddress().toString(); tp.execute(() - { System.out.println(客户端断开 clientAddr); ONLINE_CLIENTS.remove(clientAddr); System.out.println(当前在线人数 ONLINE_CLIENTS.size()); }); } Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { System.err.println(异常 cause.getMessage()); ctx.close(); } Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { String name ctx.channel().remoteAddress().toString(); tp.execute(() - { try { System.out.println(name 发来一条消息 msg); ctx.writeAndFlush(ACK_OK); } catch (Exception e) { e.printStackTrace(); } }); } }

相关文章:

IO、NIO、Netty实战

目标 客户端和服务端互相通信,本文主要是实战练习,照着敲,然后debug看为什么就行 前置理解模型核心类特点简述BIOServerSocket / Socket一个连接一个线程,accept() 和 read() 都会阻塞简单但连接多了线程爆炸NIOSelector / Server…...

Taotoken助力企业级AI应用开发,统一管理多个Agent的API成本与用量

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Taotoken助力企业级AI应用开发,统一管理多个Agent的API成本与用量 当团队同时运行多个基于不同大模型的智能体应用时&a…...

水葫芦生长周期生长阶段早晚期检测数据集VOC+YOLO格式1029张3类别

数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件)图片数量(jpg文件个数):1029标注数量(xml文件个数):1029标注数量(txt文件个数):1029标注类别…...

夏天来了TEMU爆单指南:我用凌风工具箱“标签模板“搞定夏季爆款

嘿,我是小彭,一个在跨境电商圈摸爬滚打的老玩家🙋♂️。这周在朋友圈晒出单周GMV破300万的成绩单,评论区直接炸了:"你这波操作可以啊""啥时候开个课教教我们"。说实话,真没什么高深技巧…...

抖音下载工具终极指南:如何免费保存视频、直播和合集内容

抖音下载工具终极指南:如何免费保存视频、直播和合集内容 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback su…...

第37天:SQL详解之DDL

Python学习100天(从入门到精通系列文章) 文章目录 Python学习100天(从入门到精通系列文章) 前言 一、SQL概述 1.1 建库建表 1.2 DDL关键注意事项 二、存储引擎对比 三、数据类型选择 四、删除表和修改表 4.1 删除表 4.2 修改表 总结 前言 在前一篇文章中,我们了解了关系型…...

通过Taotoken审计日志功能追踪团队API使用情况的实际案例

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 通过Taotoken审计日志功能追踪团队API使用情况的实际案例 1. 背景与需求 在团队协作开发中,多个成员或项目共享大模型…...

上班族开例会懒得记要点?2026年这3款AI总结工具,会后自动整理纪要

做互联网运营四年,开会已经成了每天的常态。部门周例会、项目复盘会、线上培训课、远程沟通会,大大小小的视频会议一场接一场。以前最让我头疼的不是参会,而是会后整理纪要。开会时既要认真听讨论、跟进工作进度,又要低头飞速记笔…...

RabbitMQ 入门与安装

RabbitMQ 入门与安装:从 MQ 概念到环境搭建 一、开篇:学习 RabbitMQ 前需要准备什么 RabbitMQ 属于消息中间件,是 Java 后端开发中非常常见的一类基础组件。学习它之前,最好已经具备以下基础: 具备一定 Java 基础&…...

用 Excel 手算一个 1-6-1 MLP:前向传播、损失、反向传播与参数更新

计算示例:本文用一个单输入、6 个隐藏神经元、单输出的多层感知机(MLP)作为例子,展示如何用 Excel 公式完整复现一次训练迭代。配套 Excel 文件中的“MLP计算过程”工作表已经把前向传播、损失计算、反向传播梯度和参数更新全部写…...

3步快速上手:抖音去水印批量下载器完整指南

3步快速上手:抖音去水印批量下载器完整指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support. 抖音批…...

B站视频下载终极指南:5步掌握免费批量下载技巧

B站视频下载终极指南:5步掌握免费批量下载技巧 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/bi/Bilib…...

百考通:AI一键生成期刊论文写作,全流程智能化支撑,让学术创作更高效

在学术研究领域,期刊论文的撰写是成果输出的关键环节,却也让众多科研工作者与学生倍感压力:选题迷茫、逻辑梳理困难、格式规范复杂、内容提炼耗时,严重拖慢了学术成果的发表节奏。百考通(https://www.baikaotongai.com…...

Midscene.js技术深度解析:视觉驱动UI自动化的架构演进与实践路径

Midscene.js技术深度解析:视觉驱动UI自动化的架构演进与实践路径 【免费下载链接】midscene AI-powered, vision-driven UI automation for every platform. 项目地址: https://gitcode.com/GitHub_Trending/mid/midscene 在传统UI自动化测试领域&#xff0c…...

深信服发布AI算力网关,聚焦AI算力治理,让AI算力效能更高

中国AI产业正在全面爆发,各行业的Agent应用发展更是迅猛。对企业来说,管好这些Agent并不容易,首先难算清的就是“成本账”——算力使用情况看不清、Token资源浪费管不住、AI投入省不下。为了帮助各行业用户实现AI模型和算力的高效治理&#x…...

Spek音频频谱分析器:如何免费快速可视化音频频率的秘密世界

Spek音频频谱分析器:如何免费快速可视化音频频率的秘密世界 【免费下载链接】spek Acoustic spectrum analyser 项目地址: https://gitcode.com/gh_mirrors/sp/spek Spek是一款功能强大的开源音频频谱分析工具,能够将复杂的音频信号转换为直观的彩…...

+86环境下“纸飞机“登录异常排查:第三方开源客户端的认证与网络适配测试

近期在针对一款基于 MTProto 协议的即时通讯工具进行客户端适配测试时,发现其官方版本在 86 号段环境下存在较为突出的登录与连接稳定性问题。本文记录问题复现过程,以及基于开源代码二次开发的优化实践。一、登录异常现象在 86 手机号、新设备登录场景下…...

SQL 排序分页精讲!ORDER BY+LIMIT 全套用法,报表分页

前言学会了条件查询、模糊查询之后,日常业务还有两个刚需场景:查出来的数据杂乱无章,想按年龄、时间、金额从小到大 / 从大到小排序;数据有成千上万条,一次性加载全部卡死,需要分页展示,一页只展…...

曼德勃罗集的 Three.js 实现

效果预览 经典的曼德勃罗集(Mandelbrot Set)分形渲染,配合动态缩放动画探索分形边界的无限细节。使用线性插值平滑着色,呈现出彩虹般的色彩过渡。 👉 点击查看《曼德勃罗集的》完整源码与效果演示 Shader 实现原理…...

SQL 模糊查询 + NULL 空值。LIKE 通配符 % 和_、IS NULL

前言学会精准条件查询后,工作中又会遇到新难题:需要按关键词模糊搜索,比如搜姓张、名字带 “明” 的用户,不会写 LIKE;分不清 % 和 _ 两个通配符到底有什么区别,经常用错;数据表有空值 NULL&…...

三国杀卡牌DIY终极指南:5分钟打造你的专属武将

三国杀卡牌DIY终极指南:5分钟打造你的专属武将 【免费下载链接】Lyciumaker 在线三国杀卡牌制作器 项目地址: https://gitcode.com/gh_mirrors/ly/Lyciumaker 还在羡慕别人能设计出酷炫的三国杀武将卡牌吗?Lyciumaker这个免费开源的三国杀卡牌制作…...

让Windows 11任务栏唱歌:Taskbar-Lyrics插件如何改变你的音乐体验

让Windows 11任务栏唱歌:Taskbar-Lyrics插件如何改变你的音乐体验 【免费下载链接】Taskbar-Lyrics BetterNCM插件,在任务栏上嵌入歌词,目前仅建议Windows 11 项目地址: https://gitcode.com/gh_mirrors/ta/Taskbar-Lyrics 还在为切换…...

C语言学习笔记20260522—交换两个整数的值(地址传递)/打印1-100直接3倍数的数字/两个数最大公约数(最小公倍数)

一.知识点 函数需要改变实参时,必要要用地址传递,不能用值传递。当一个数%比自己大的数是,%的值就是自己本身。数辗转相除法(欧几里得算法)求两个数的最大公约数。两个数的最小公倍数为两个数的乘积除以最大公约数。 二…...

数据库锁机制:表锁、行锁(Oracle 默认)、共享锁、排他锁、乐观锁、悲观锁、死锁、Hive 中的锁

数据库锁机制是控制并发访问数据的关键技术。本文系统介绍了锁的概念、分类和应用场景:1)锁通过限制并发访问确保数据一致性,类比厕所门锁机制;2)按粒度分为表锁(适合批量操作)、行锁&#xff0…...

GEO学习能帮我提高AI搜索排名吗?

先直接回答这个问题:GEO不叫"排名",但效果比排名更直接。如果你理解了这句话,你就理解了GEO和SEO的本质区别。AI搜索没有"排名",只有"引用"传统SEO优化的目标是在搜索结果页面占据靠前位置——第几…...

CANN Rotary Embedding 融合算子:解锁千问大模型推理性能的 3 倍密钥

CANN Rotary Embedding 融合算子:解锁千问大模型推理性能的 3 倍密钥 导语:在大模型推理的“微操”中,位置编码(Positional Encoding)往往被视为理所当然的开销。然而,在昇腾(Ascend&#xff0…...

DeepSeek V2安全对齐能力深度拆解(含对抗攻击测试报告+合规审计清单)

更多请点击: https://codechina.net 第一章:DeepSeek V2安全对齐能力深度拆解(含对抗攻击测试报告合规审计清单) DeepSeek V2 在设计阶段即嵌入多层安全对齐机制,涵盖输入过滤、策略蒸馏、响应重加权与后验校验四大核…...

Agent 场景落地:从概念演示到真实服务

当下 Agent 概念火热,但多数仍停留在实验室演示、概念展示阶段:发布会效果惊艳,却难以真正走进银行、门店、家庭等真实服务场景,解决实际问题。 行业共识逐渐清晰:Agent 的价值不在酷炫演示,而在真实场景里…...

Veo生成模糊/断帧/色偏?立刻停用默认设置!20年视频架构师紧急发布的5项必改Veo 2K/4K硬核配置

更多请点击: https://intelliparadigm.com 第一章:Veo 2K/4K视频生成质量崩塌的根源诊断 当Veo模型在2K或4K分辨率下输出视频时,高频细节严重丢失、运动伪影显著增强、纹理结构模糊化,这一现象并非单纯算力不足所致,而…...

如何为你的推特内容创作工具配置Taotoken大模型API

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 如何为你的推特内容创作工具配置Taotoken大模型API 假设你是一名社交媒体运营者,正在使用或开发一个自动生成推特文案的…...