[AIGC] 快速掌握Netty,打造高性能IM服务器!

news/2024/3/4 10:41:57

前言:Netty 是一个非常优秀的网络应用程序框架,支持高并发、高性能的网络通信,适用于开发各种服务器程序,如即时通讯、游戏、物联网等。使用 Netty 可以大大提升服务器程序的性能和可靠性。本文将介绍 Netty 的基本原理和使用方法,并给出一个简单的 IM 程序示例,帮助读者快速掌握 Netty 的使用。


文章目录

  • 一、什么是Netty?
  • 二、为什么使用 Netty?
  • 三、怎么使用 Netty?
  • 四、Netty 实现一个IM程序
  • 总结

一、什么是Netty?

Netty是一个高性能、事件驱动的网络应用程序框架,基于 Java NIO (Non-blocking I/O) 开发。它主要用于开发高性能的服务器程序,例如即时通讯、游戏、物联网等。

二、为什么使用 Netty?

使用 Netty 的主要原因包括:

  1. 高性能:基于 Java NIO 实现,支持高并发,I/O 处理能力强,同时在可用性方面有一定的优化。

  2. 高可靠性:充分利用 Java NIO 机制,避免 I/O 阻塞,提高应用程序的可用性。

  3. 易于开发:提供了丰富的 API 和开发文档,API 使用简单易懂,易于上手。

  4. 可扩展性强:可自定义编解码器、拦截器、消息处理器等,可以很方便地扩展新的协议。

  5. 支持多种协议:支持 TCP/UDP、HTTP、WebSocket 等多种协议。

三、怎么使用 Netty?

使用 Netty 主要需要进行以下几个步骤:

  1. 创建服务器启动类,配置服务器的参数和启动程序。

  2. 编写客户端连接请求处理类,处理客户端连接请求,建立连接。

  3. 编写消息处理类,对客户端发送的消息进行解码和处理。

  4. 编写消息编码类,将服务器的响应消息编码成二进制数据。

  5. 实现客户端和服务器之间的数据交互,完成数据的发送和接收。

四、Netty 实现一个IM程序

以下是一个使用 Netty 实现的简单的 IM 程序,支持用户登录、发送消息、退出的功能。

public class NettyIMServer {public static void main(String[] args) throws Exception {// 创建 ServerBootstrapServerBootstrap bootstrap = new ServerBootstrap();// 配置 EventLoopGroupEventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();// 解码器pipeline.addLast(new StringDecoder());// 编码器pipeline.addLast(new StringEncoder());// 消息处理器pipeline.addLast(new NettyIMServerHandler());}});// 绑定端口ChannelFuture future = bootstrap.bind(8888).sync();System.out.println("Server started and listen on: " + future.channel().localAddress());// 等待服务器监听端口关闭future.channel().closeFuture().sync();} finally {// 释放资源bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}static class NettyIMServerHandler extends SimpleChannelInboundHandler<String> {private static final Map<String, Channel> clients = new ConcurrentHashMap<>();@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {// 获取 ChannelChannel channel = ctx.channel();// 判断消息类型if (msg.startsWith("[Login]")) {// 登录消息,获取用户名String username = msg.substring(7);System.out.println("用户[" + username + "]登录了");// 将用户信息保存到 clients map 中clients.put(username, channel);} else if (msg.startsWith("[Logout]")) {// 退出消息,获取用户名String username = msg.substring(8);System.out.println("用户[" + username + "]退出了");// 将用户信息从 clients map 中移除clients.remove(username);} else if (msg.startsWith("[SendTo]")) {// 发送消息,格式为 [SendTo]:[username]:[message]String[] parts = msg.split(":", 3);String to = parts[1];String message = parts[2];// 获取发送者用户名String from = clients.entrySet().stream().filter(entry -> channel.equals(entry.getValue())).map(Map.Entry::getKey).findFirst().orElse("unknown");// 查找接收者Channel toChannel = clients.get(to);if (toChannel != null) {// 发送消息给接收者toChannel.writeAndFlush("[" + from + "]: " + message + "\n");} else {// 接收者不存在,发送错误消息给发送者channel.writeAndFlush("[Error]: User not found\n");}}}@Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {System.out.println("客户端[" + ctx.channel().remoteAddress() + "]连接成功");super.handlerAdded(ctx);}@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) throws Exception {System.out.println("客户端[" + ctx.channel().remoteAddress() + "]断开连接");super.handlerRemoved(ctx);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {System.out.println("客户端[" + ctx.channel().remoteAddress() + "]发生异常:" + cause.getMessage());super.exceptionCaught(ctx, cause);}}
}

这段程序是一个基于 Netty 的简单的 IM(即时通讯)服务器程序,它可以实现用户登录、退出和发送消息等功能。

程序主要分为两部分,第一部分是服务器的启动,第二部分是消息处理器。

在服务器启动部分,程序首先创建了一个 ServerBootstrap 实例,该实例用于启动服务器。然后配置了两个 EventLoopGroup 实例,一个用于接收客户端连接,一个用于处理客户端请求。接着使用 bootstrap.group() 方法将两个 EventLoopGroup 实例关联起来,并指定服务器的 Channel 类型为 NioServerSocketChannel。最后使用 childHandler() 方法设置消息的处理器。

在消息处理器部分,程序首先定义了一个 Map 类型的 clients 对象,用于保存客户端的信息。然后重写了 channelRead0() 方法,该方法会在客户端发送消息时被调用。在该方法中,程序根据消息内容判断消息类型,并执行相应的逻辑。

如果是登录消息,则从消息中提取出用户名,并将其保存到 clients 对象中;如果是退出消息,则从消息中提取出用户名,并从 clients 对象中移除该用户;如果是发送消息,则从消息中提取出接收者和消息内容,并通过 clients 对象查找接收者的 Channel,然后将消息发送给接收者。在发送消息时,程序还会将发送者的用户名添加到消息前面,以便接收者知道消息是由谁发送的。

此外,程序还重写了 handlerAdded()、handlerRemoved() 和 exceptionCaught() 方法,用于处理客户端连接和异常。在 handlerAdded() 方法中,程序会记录客户端连接成功的事件;在 handlerRemoved() 方法中,程序会记录客户端断开连接的事件;在 exceptionCaught() 方法中,程序会记录客户端发生异常的事件。

总结

Netty 是一个高性能、事件驱动的网络应用程序框架,可以用于开发高性能的服务器程序,例如即时通讯、游戏、物联网等。使用 Netty 可以获得高性能、高可靠性、易于开发、可扩展性强、支持多种协议的优点。

使用 Netty 主要需要进行以下几个步骤:创建服务器启动类,配置服务器的参数和启动程序;编写客户端连接请求处理类,处理客户端连接请求,建立连接;编写消息处理类,对客户端发送的消息进行解码和处理;编写消息编码类,将服务器的响应消息编码成二进制数据;实现客户端和服务器之间的数据交互,完成数据的发送和接收。

本文还介绍了一个使用 Netty 实现的简单的 IM 程序,支持用户登录、发送消息、退出的功能。该程序主要分为服务器的启动和消息处理器两部分,可以作为学习 Netty 和 IM 服务器的入门示例。


http://www.ppmy.cn/news/1131573.html

相关文章

第 114 场 LeetCode 双周赛题解

A 收集元素的最少操作次数 模拟: 反序遍历数组&#xff0c;用一个集合存当前遍历过的不超过 k k k 的正数 class Solution { public:int minOperations(vector<int> &nums, int k) {unordered_set<int> vis;int n nums.size();int i n - 1;for (;; i--) {if…

设计模式之抽象工厂模式--创建一系列相关对象的艺术(简单工厂、工厂方法、到抽象工厂的进化过程,类图NS图)

目录 概述概念适用场景结构类图 衍化过程业务需求基本的数据访问程序工厂方法实现数据访问程序抽象工厂实现数据访问程序简单工厂改进抽象工厂使用反射抽象工厂反射配置文件衍化过程总结 常见问题总结 概述 概念 抽象工厂模式是一种创建型设计模式&#xff0c;它提供了一种将相…

GD32F10x的输出模式

1. 单片机型号的识别。 2. GPIO的输出模式。 1. 开漏模式 2.推挽模式 3.复用开漏模式 4.复用推挽模式。 开漏模式&#xff1a;&#xff08;写入位设置&#xff0c;输出数据寄存器来控制MOS&#xff09; 只有N-MOS管导通。PMOS不导通。 当N-MOS的栅极为0&#xff0c;N-MOS管…

Flutter笔记:关于应用程序中提交图片作为头像

Flutter笔记 关于应用程序中提交图片作为头像 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/133418554…

LeetCode 460. LFU 缓存

原题链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题目描述 请你为 最不经常使用&#xff08;LFU&#xff09;缓存算法设计并实现数据结构。 实现 LFUCache 类&#xff1a; LFUCache(int capacity) - 用数据结构的容量 capacity 初…

83、SpringBoot --- 下载和安装 MSYS2、 Redis

启动redis服务器&#xff1a; 打开小黑窗&#xff1a; C:\Users\JH>e: E:>cd E:\install\Redis6.0\Redis-x64-6.0.14\bin E:\install\Redis6.0\Redis-x64-6.0.14\bin>redis-server.exe redis.windows.conf 启动redis客户端&#xff1a; 小黑窗&#xff1a;redis-cli …

正点原子嵌入式linux驱动开发——STM32MP1启动详解

STM32单片机是直接将程序下载到内部 Flash中&#xff0c;上电以后直接运行内部 Flash中的程序。 STM32MP157内部没有供用户使用的 Flash&#xff0c;系统都是存放在外部 Flash里面的&#xff0c;比如 EMMC、NAND等&#xff0c;因此 STM32MP157上电以后需要从外部 Flash加载程序…

Stm32_标准库_5_呼吸灯_按键控制

Stm32按键和输出差不多 PA1为LED供给正电&#xff0c;PB5放置按键&#xff0c;按键一端接PB5,另一端接负极 void Key_Init(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //APB2总线连接着GPIOBGPIO_InitStructur.GPIO_Mode GPIO_Mode_IPU;GPIO_InitStructur.…

Spring的配置Bean的方式

在Spring框架中&#xff0c;配置Bean有三种主要方式&#xff1a;自动装配、基于Java的显式配置和基于XML的显式配置。 1、自动装配&#xff1a; 自动装配是Spring容器根据Bean之间的依赖关系&#xff0c;自动将需要的Bean注入到目标Bean中。这是一种非常简便和快捷的配置方式&…

简单三步 用GPT-4和Gamma自动生成PPT PDF

1. 用GPT-4 生产PPT内容 我想把下面的文章做成PPT&#xff0c;请你给出详细的大纲和内容 用于谋生的知识&#xff0c;学生主要工作是学习&#xff0c;成年人的工作是养家糊口&#xff0c;这是基本的要求&#xff0c;在这之上&#xff0c;才能有更高的追求。 不要短期期望过高…

zemax光线光扇图

光线光扇图&#xff1a; 过光瞳Y轴的光束剖面&#xff0c;称为子午光扇&#xff1b; 过光瞳X轴的光束剖面&#xff0c;称为弧矢光扇。 可以显示作为光瞳坐标函数的光线像差。 对于视场内任意一点&#xff0c;取其子午面内的光线&#xff0c;以光线在光阑面上的透射点坐标为横…

STM32三种开发方式及标准库和HAL库的编程差异

三种开发方式 STM32基于标准库函数和HAL库编程差异_stm32库函数和hal库-CSDN博客本文目的是以串口通信来简要分析STM32使用标准库函数和HAL库函数编程的差异。目录&#xff08;一&#xff09;开发方式1.配置寄存器2.库函数3.HAL库&#xff08;二&#xff09;库函数与HAL库对比…

【面试经典150 | 数组】加油站

文章目录 写在前面Tag题目来源题目解读解题方法方法一&#xff1a;暴力枚举方法二&#xff1a;一次遍历 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些…

Kafka(一)使用Docker Compose安装单机Kafka以及Kafka UI

文章目录 Kafka中涉及到的术语Kafka镜像选择Kafka UI镜像选择Docker Compose文件Kafka配置项说明KRaft vs Zookeeper和KRaft有关的配置关于Controller和Broker的概念解释Listener的各种配置 Kafka UI配置项说明 测试Kafka集群Docker Compose示例配置 Kafka中涉及到的术语 对于…

maven无法下载时的解决方法——笔记

右键项目然后点击创建setting.xml&#xff08;因为现在创建了&#xff0c;所以没显示了&#xff0c;可以直接点击打开setting.xml&#xff09; 然后添加 <mirror><id>nexus-aliyun</id><mirrorOf>*,!jeecg,!jeecg-snapshots</mirrorOf><name…

2023年中国艺术涂料市场发展历程及趋势分析:艺术涂料市场规模将进一步扩大[图]

艺术涂料是一种用于绘画和装饰&#xff0c;具有各种纹理或通过涂装手段后具有高装饰性的新型涂料。由于具有高度饱和的颜色、良好的遮盖力和可塑性&#xff0c;呈现立体装饰效果好、色彩搭配适当、风格独具特色的特点&#xff0c;而使得涂装出的饰面自然贴合、更加美观漂亮&…

玩转数据-大数据-Flink SQL 中的时间属性

一、说明 时间属性是大数据中的一个重要方面&#xff0c;像窗口&#xff08;在 Table API 和 SQL &#xff09;这种基于时间的操作&#xff0c;需要有时间信息。我们可以通过时间属性来更加灵活高效地处理数据&#xff0c;下面我们通过处理时间和事件时间来探讨一下Flink SQL …

【ARMv8 SIMD和浮点指令编程】NEON 加载指令——如何将数据从内存搬到寄存器(LDxLDxR)?

将内存中的数据搬到 NEON 寄存器,有很多指令可以完成,熟悉这些指令是必须的。 1 LD1 (multiple structures) 将多个单元素结构加载到一个,两个,三个或四个寄存器上。该指令从内存中加载多个单元结构,并将结果写入一、二、三或四个 SIMD&FP 寄存器。 无偏移 一个寄存…

第十三章 类和对象——对象的初始化和清理

生活中我们买的电子产品都基本会有出厂设置&#xff0c;在某一天我们不用时候也会删除一些自己信息数据保证安全 C中的面向对象来源于生活&#xff0c;每个对象也都会有初始设置以及 对象销毁前的清理数据的设置。 一、构造函数和析构函数 对象的初始化和清理也是两个非常重…

【数据结构】队列实现+层序遍历详解+一些练题

欢迎来到我的&#xff1a;世界 希望作者的文章对你有所帮助&#xff0c;有不足的地方还请指正&#xff0c;大家一起学习交流 ! 目录 前言队列的实现层序遍历详解强化练习1.判断是不是完全二叉树求二叉树的最大深度 总结 前言 国庆到了&#xff0c;也要内卷一下&#xff0c;感…
最新文章