Netty网络聊天室及扩展序列化算法

一、前言

Netty是一个基于Java的高性能、事件驱动的网络应用框架,广泛应用于各种网络通信场景。本文将介绍如何使用Netty构建一个简单的网络聊天室,并扩展序列化算法来提高数据传输效率和灵活性。

二、Netty网络聊天室的实现

1. 项目结构

我们将使用Maven构建项目,项目结构如下:

netty-chatroom/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   ├── server/
│   │   │   │   ├── ChatServer.java
│   │   │   │   ├── ChatServerInitializer.java
│   │   │   │   ├── ChatServerHandler.java
│   │   │   ├── client/
│   │   │   │   ├── ChatClient.java
│   │   │   │   ├── ChatClientInitializer.java
│   │   │   │   ├── ChatClientHandler.java
│   │   ├── resources/
│   │       ├── log4j.properties
├── pom.xml
​

2. 服务器端实现

ChatServer.java
package server;import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;public class ChatServer {private final int port;public ChatServer(int port) {this.port = port;}public void start() throws Exception {NioEventLoopGroup bossGroup = new NioEventLoopGroup();NioEventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChatServerInitializer()).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);ChannelFuture f = b.bind(port).sync();f.channel().closeFuture().sync();} finally {workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();}}public static void main(String[] args) throws Exception {new ChatServer(8080).start();}
}
​
ChatServerInitializer.java
package server;import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;public class ChatServerInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));ch.pipeline().addLast(new StringDecoder());ch.pipeline().addLast(new StringEncoder());ch.pipeline().addLast(new ChatServerHandler());}
}
​
ChatServerHandler.java
package server;import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;public class ChatServerHandler extends SimpleChannelInboundHandler<String> {private static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);@Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {channels.add(ctx.channel());}@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) throws Exception {channels.remove(ctx.channel());}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {for (var channel : channels) {if (channel != ctx.channel()) {channel.writeAndFlush("[Client] " + ctx.channel().remoteAddress() + " says: " + msg + "\n");} else {channel.writeAndFlush("[You] " + msg + "\n");}}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}
​

3. 客户端实现

ChatClient.java
package client;import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;public class ChatClient {private final String host;private final int port;public ChatClient(String host, int port) {this.host = host;this.port = port;}public void start() throws Exception {NioEventLoopGroup group = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).handler(new ChatClientInitializer());ChannelFuture f = b.connect(host, port).sync();f.channel().closeFuture().sync();} finally {group.shutdownGracefully();}}public static void main(String[] args) throws Exception {new ChatClient("localhost", 8080).start();}
}
​
ChatClientInitializer.java
package client;import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;public class ChatClientInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));ch.pipeline().addLast(new StringDecoder());ch.pipeline().addLast(new StringEncoder());ch.pipeline().addLast(new ChatClientHandler());}
}
​
ChatClientHandler.java
package client;import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;public class ChatClientHandler extends SimpleChannelInboundHandler<String> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {System.out.println(msg);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}
​

三、扩展序列化算法

为了提高数据传输效率,我们可以扩展Netty的序列化算法。Netty默认提供的序列化算法包括Java序列化、JSON、Protobuf等。下面介绍如何使用Protobuf进行序列化。

1. 配置Protobuf

首先,在 pom.xml中添加Protobuf依赖:

<dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>3.19.1</version>
</dependency>
​

2. 定义Protobuf消息

创建一个 chat.proto文件:

syntax = "proto3";package chat;message ChatMessage {string from = 1;string to = 2;string content = 3;
}
​

编译Protobuf文件生成Java类:

protoc --java_out=src/main/java src/main/proto/chat.proto
​

3. 修改服务器端处理器

在服务器端,使用Protobuf进行消息的序列化和反序列化:

package server;import chat.ChatMessage;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;public class ChatServerHandler extends SimpleChannelInboundHandler<ChatMessage> {private static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);@Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {channels.add(ctx.channel());}@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) throws Exception {channels.remove(ctx.channel());}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, ChatMessage msg) throws Exception {for (var channel : channels) {if (channel != ctx.channel()) {channel.writeAndFlush(msg.toBuilder().setContent("[Client] " + ctx.channel().remoteAddress() + " says: " + msg.getContent()).build());} else {channel.writeAndFlush(msg.toBuilder().setContent("[You] " + msg.getContent()).build());}}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}
​

4. 修改客户端处理器

在客户端,同样使用Protobuf进行消息的序列化和反序列化:

package client;import chat.ChatMessage;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;public class ChatClientHandler extends SimpleChannelInboundHandler<ChatMessage> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, ChatMessage msg) throws Exception {System.out.println(msg.getContent());}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}

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

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

相关文章

基于单片机金沙河粮仓环境监测系统设计与实现

摘 要 本文围绕基于单片机的金沙河粮仓环境监测系统展开设计与实现研究。系统以单片机为核心&#xff0c;集成 DHT11、MQ - 135 等传感器&#xff0c;可实时精准监测粮仓温湿度、气体成分等关键环境参数。借助 LoRa、ESP8266 实现数据的可靠传输与远程通信 &#xff0c;OLED 屏…

如何解决Android Studio安装时无法下载SDK的问题(Windows、Linux、Mac解决方案大全)

如何解决Android Studio安装时无法下载SDK的问题&#xff08;Windows、Linux、Mac解决方案大全&#xff09; 前言 对于全栈开发者而言&#xff0c;安装 Android Studio 是迈向 Android 开发的第一步&#xff0c;但在 Windows、Linux、macOS 等不同平台上&#xff0c;经常会遇…

SQL Server从入门到项目实践(超值版)读书笔记 21

9.5 数据的内连接查询连接是关系数据库模型的主要特点&#xff0c;连接查询是关系数据库中最主要的查询&#xff0c;主要包括内连接、外连接等。内连接查询操作列出与连接条件匹配的数据行&#xff0c;它使用比较运算符比较被链接列的列值。具体语法格式如下&#xff1a;SELECT…

瑞芯微7月17日举办开发者大会,多款AIoT新品发布,触觉智能RK方案商报导

瑞芯微第九届开发者大会RKDC 2025将有多款新品发布。 据瑞芯微电子Rockchip此前宣布&#xff1a;该企业的本年度开发者大会RKDC 2025将于7月17~18日在福建福州海峡国际会展中心举行。本次瑞芯微开发者大会以“AIoT模型创新重做产品”为主题&#xff0c;关注传统IoT功能设备向场…

Eureka+Ribbon实现服务注册与发现

目录 一、相关文章 二、兼容说明 三、服务注册 四、服务发现 一、相关文章 基础工程&#xff1a;gradle7.6.1springboot3.2.4创建微服务工程-CSDN博客 Eureka服务端启动&#xff1a;https://blog.csdn.net/cherishSpring/article/details/149473554 Ribbon负载均衡&#…

数据库、HTML

一、数据库 数据库文件与普通文件区别: 普通文件对数据管理(增删改查)效率低2.数据库对数据管理效率高&#xff0c;使用方便 常用数据库: 1.关系型数据库: 将复杂的数据结构简化为二维表格形式 大型:0racle、DB2 中型:MySq1、sQLServer 小型:Sqlite 2.非关系型数据库以键值对…

RCE随笔(1)

哪些是可以执行代码执行&#xff1a;php代码。eval如&#xff1a;eval:<?php eval($_post[key]);eval&#xff1a;php中不被叫做函数叫动态执行命令assert&#xff1a;执行函数call_user_func_array<?php call_user_func_array(assert,array($_REQUEST[shu]));传入xxs-…

FPGA——ZYNQ7020学习日记(PS端)4(开始PS控制VGA显示)

1.DMA 我们的整体VGA显示分为几步&#xff1a;比如先导入VIDEO TIMING CONTROL来做对输入数据的时序“对齐”&#xff0c;这里开源骚客写的很详细&#xff0c;先用了一个虚拟IO&#xff08;VIO)来作为输入&#xff0c;导入了一个简单的RTL模块&#xff08;当VTL的使能信号有效…

AGX Xavier 搭建360环视教程【补充一:鱼眼去畸变(Fisheye Undistortion)】

对每路帧做鱼眼去畸变除了用cv::cuda::remap是否有更好的办法呢&#xff1f;确实 cv::cuda::remap 不是唯一可选项&#xff0c;甚至未必是最高效或最适合实际业务量级的方案。&#x1f3af; 1️⃣ 去畸变的原理鱼眼相机&#xff08;或者大广角相机&#xff09;会把直线拉弯&…

tomato靶机练习

下载完靶机后&#xff0c;直接运行&#xff0c;选择安装路径后将虚拟机的网络设置为nat模式&#xff0c;设置完成后重启虚拟机扫描同一网段&#xff0c;查找主机&#xff0c;这里我们使用kali的nmap&#xff0c;既能找到主机&#xff0c;也能查看开启的端口依次尝试&#xff0c…

136. Java 泛型 - 下限通配符

文章目录136. Java 泛型 - 下限通配符 (? super T)**1. 什么是下限通配符 (? super T)&#xff1f;****2. 为什么使用下限通配符&#xff1f;****3. 示例&#xff1a;使用 ? super Integer 允许添加 Integer****✅ 正确示例****4. 为什么 List<? super Integer> 和 L…

C++23中的std::expected:异常处理

C23中的std::expected:异常处理 众所周知&#xff0c;C23以前的异常处理是比较麻烦的&#xff0c;尤其是自己要在可能抛出异常的地方&#xff0c;需要自己去捕获它&#xff0c;比如除数为0的异常、使用std::stoi函数将字符串转换成int整型数据、处理文件读写的异常等等&#x…

处理Electron Builder 创建新进程错误 spawn ENOMEM

这个错误 spawn ENOMEM 表明系统内存不足&#xff0c;无法为 Electron Builder 创建新进程。以下是一些可能的解决方案&#xff1a;释放系统内存关闭不必要的程序和服务增加物理内存 (RAM) 或交换空间 (swap)使用 free -h 和 top 命令检查内存使用情况临时增加交换空间# 创建一…

discuz安装使用教程,及网站部署在公网访问

Discuz!的安装主要包括环境准备、程序部署和配置管理三个核心步骤‌&#xff0c;有条件 的可以使用宝塔面板或云镜像简化流程&#xff0c;本地部署无公网IP的配合类似nat123映射公网访问&#xff0c;当前最新版本为Discuz! Q&#xff08;2025年发布&#xff09;和Discuz! X3.5&…

深入解析C#数字转换:隐式与显式转换的全面指南

—— 数据精度保卫战中的checked与unchecked秘籍 &#x1f4cc; 核心概念速览 1. 隐式转换 自动发生&#xff0c;无数据丢失风险&#xff08;如 int→long&#xff09;遵循"小类型→大类型"路径&#xff08;见下图⬇️&#xff09; [图1&#xff1a;C#隐式数字转换路…

量子计算可以解决的三个现实问题

今年是量子力学被发现一百周年。这一突破帮助人们认识到&#xff0c;支配我们周围世界最小层面&#xff08;分子、原子和亚原子粒子&#xff09;的物理定律&#xff0c;与支配我们在日常生活中与物体相互作用方式的物理定律有着根本的不同。量子力学让我们能够了解从血液中的新…

Valgrind Memcheck 全解析教程:6个程序说明基础内存错误

Valgrind 是一个强大的动态分析框架&#xff0c;其中的 memcheck 工具用于检测 C/C 程序中类型不定的内存错误&#xff0c;是基础级内存调试工具的重要选择。 本文将通过 6 段有意义的错误代码&#xff0c;全面讲解 memcheck 的检测原理和输出分析&#xff0c;进而帮助学习者托…

Vue3 实现 Excel 文件导入导出功能

在Vue 3中实现Excel文件的导入和导出功能&#xff0c;你可以使用一些流行的JavaScript库&#xff0c;如SheetJS&#xff08;也称为xlsx&#xff09;来处理Excel文件。以下是实现这一功能的基本步骤&#xff1a;1. 安装SheetJS首先&#xff0c;你需要安装xlsx库。在你的Vue项目中…

CS231n-2017 Lecture2图像分类笔记

图像分类问题定义&#xff1a;在已有固定的分类标签集合的前提下&#xff0c;能够对输入的图像进行识别处理&#xff0c;从集合中找到该图像所对应的标签。对于计算机而言&#xff0c;图像并非直观的图像&#xff0c;而是一个的像素集合&#xff0c;对于每个像素&#xff0c;其…

Typecho博客Ajax评论功能实现全攻略

文章目录 Typecho实现Ajax评论功能的完整指南 引言 一、技术选型与准备工作 1.1 技术栈分析 1.2 环境准备 二、前端实现方案 2.1 基础HTML结构 2.2 JavaScript处理逻辑 三、后端处理实现 3.1 创建插件处理Ajax请求 3.2 错误处理增强 四、安全性考虑 4.1 CSRF防护 4.2 输入过滤 …