运用netty框架实现自定义协议并运用于简易聊天

article/2025/9/21 9:32:53

1.什么是netty


Netty 是由 JBOSS 提供的一个 Java 开源框架。Netty 提供异步的、基于事件驱动的网络应用程序框架,用以快速开发高性能、高可靠性的网络 IO 程序,是目前最流行的 NIO 框架,Netty 在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用,知名的 Elasticsearch 、Dubbo 框架内部都采用了 Netty。

2.Netty的优点


Netty 对 JDK 自带的 NIO 的 API 进行了封装,解决了上述问题。

1.设计优雅:适用于各种传输类型的统一 API 阻塞和非阻塞 Socket;基于灵活且可扩展的事件模型,可以清晰地分离关注点;高度可定制的线程模型 - 单线程,一个或多个线程池.

2.使用方便:详细记录的 Javadoc,用户指南和示例;没有其他依赖项,JDK 5(Netty 3.x)或 6(Netty 4.x)就足够了。

3.高性能、吞吐量更高:延迟更低;减少资源消耗;最小化不必要的内存复制。

4.安全:完整的 SSL/TLS 和 StartTLS 支持。

5.社区活跃、不断更新:社区活跃,版本迭代周期短,发现的 Bug 可以被及时修复,同时更多的新功能会被加入

下面是代码部分:

服务端:

Manger.java

package zmc.com.Server;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;public class Manger {private static final Map<String, Set<String>> friend = new ConcurrentHashMap<>();public static void addFriend(String clientId, String friendId) {Set<String> friendList = friend.get(clientId);if (null==friendList){friendList=new HashSet<>();}friendList.add(friendId);friend.put(clientId, friendList);}public static List<String> list(String clientId) {Set<String> friendList = friend.get(clientId);if (null==friendList){return new ArrayList<>();}return new ArrayList<>(friendList);}
}

 ServerHandler.java

package zmc.com.Server;import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import zmc.com.MMessage.MyMessage;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;public class ServerHandler extends SimpleChannelInboundHandler<MyMessage> {//所有的channel存入map集合中,目的是为了私聊好获取用户private static Map<String, Channel> allChannels = new ConcurrentHashMap<String, Channel>();//格式化所有日期时间private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//转化日期private String currentDate = sdf.format(new Date());@Overridepublic void handlerAdded(ChannelHandlerContext ctx) {//获取当前channelChannel channel = ctx.channel();//推送客户加入聊天的信息推送给其它在线的客户端//该方法会将channelGroup中所有的channel遍历并发送消息allChannels.forEach(new BiConsumer<String, Channel>() {@Overridepublic void accept(String k, Channel ch) {ch.writeAndFlush(MyMessage.StringMessage(currentDate + " \n [客户端]" + channel.remoteAddress() + "加入聊天\n"));}});//获取端口号String key = channel.remoteAddress().toString().split(":")[1];allChannels.put(key, channel);}@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) {//获取当前channelChannel channel = ctx.channel();//推送客户加入聊天的信息推送给其它在线的客户端//该方法会将map中所有的channel遍历并发送消息allChannels.forEach(new BiConsumer<String, Channel>() {@Overridepublic void accept(String k, Channel ch) {ch.writeAndFlush(MyMessage.StringMessage(currentDate + " \n [客户端]" + channel.remoteAddress() + "离线\n"));}});System.out.println("当前在线人数:" + allChannels.size());}@Overridepublic void channelActive(ChannelHandlerContext ctx) {System.out.println(currentDate + " -- " + ctx.channel().remoteAddress() + "上线~");}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {Channel channel = ctx.channel();String key = channel.remoteAddress().toString().split(":")[1];allChannels.remove(key);System.out.println(currentDate + " -- " + ctx.channel().remoteAddress() + "离线");}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {//关闭ctx.close();}@Overrideprotected void channelRead0(ChannelHandlerContext channelHandlerContext, MyMessage myMessage){//获取到当前channelChannel channel = channelHandlerContext.channel();String content = myMessage.getContent().toString();return;}if (content.contains("&")) {String id = content.split("&")[1];String key = channel.remoteAddress().toString().split(":")[1];Manger.addFriend(key, id);Channel userChannel = allChannels.get(id);userChannel.writeAndFlush(myMessage);return;}//循环遍历hashmap集合进行转发消息allChannels.forEach((k, ch) -> {if (channel != ch) {myMessage.setContent(currentDate + " \n [客户端]" + channel.remoteAddress() + ":" + content + "\n");ch.writeAndFlush(myMessage);} else { // 发送消息给自己,回显自己发送的消息myMessage.setContent(currentDate + " \n [我]:" + content + "\n");channel.writeAndFlush(myMessage);}});}
}

Sserver.java 

package zmc.com.Server;import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import zmc.com.MMessage.MyDecoder;
import zmc.com.MMessage.MyEncoder;import java.util.concurrent.TimeUnit;public class Sserver {// 监听端口private int port;public Sserver(int port) {this.port = port;}//编写run方法,处理客户端的请求public void run() {//创建两个线程组EventLoopGroup bossGroup = new NioEventLoopGroup(1);//Nio核数 * 2EventLoopGroup workerGroup = new NioEventLoopGroup();ServerBootstrap bootstrap = new ServerBootstrap();try {bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {//获取pipelineChannelPipeline pipeline = socketChannel.pipeline();//自定义协议pipeline.addLast(new MyEncoder());pipeline.addLast(new MyDecoder());//加入自己的业务处理handlerpipeline.addLast(new ServerHandler());//加入心跳检测机制pipeline.addLast(new IdleStateHandler(3, 5, 7, TimeUnit.SECONDS));}});System.out.println("netty 服务器启动");ChannelFuture future = bootstrap.bind(port).sync();//监听关闭事件future.channel().closeFuture().sync();} catch (Exception e) {e.printStackTrace();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}public static void main(String[] args) {Sserver groupChatServer = new Sserver(8001);groupChatServer.run();}
}

 客服端:

Cclient.java

package zmc.com.Client;public class Cclient {public static void main(String[] args) {ClientChannel groupChatClient = new ClientChannel("127.0.0.1", 8001);groupChatClient.run();}
}

ClientChannel.java 

package zmc.com.Client;import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import zmc.com.MMessage.MyMessage;
import zmc.com.MMessage.MyDecoder;
import zmc.com.MMessage.MyEncoder;import java.util.Scanner;public class ClientChannel {//定义属性private final String host;public final int port;public ClientChannel(String host, int port) {this.host = host;this.port = port;}public void run() {EventLoopGroup eventExecutors = new NioEventLoopGroup();Bootstrap bootstrap = new Bootstrap();try {bootstrap.group(eventExecutors).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {//得到pipelineChannelPipeline pipeline = socketChannel.pipeline();pipeline.addLast(new MyEncoder());pipeline.addLast(new MyDecoder());//加入自定义handlerpipeline.addLast(new ClientHandler());}});ChannelFuture channelFuture = bootstrap.connect(host, port).sync();//得到channelChannel channel = channelFuture.channel();System.out.println("-----" + channel.localAddress() + "----");//客户端需要输入信息,创建一个扫描器Scanner scanner = new Scanner(System.in);while (scanner.hasNext()) {String msg = scanner.nextLine();//通过channel发送到服务器端channel.writeAndFlush(MyMessage.StringMessage(msg));}channelFuture.channel().closeFuture().sync();} catch (Exception e) {} finally {eventExecutors.shutdownGracefully();}}}

ClientHandler.java 

package zmc.com.Client;import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import zmc.com.MMessage.MyMessage;public class ClientHandler extends SimpleChannelInboundHandler<MyMessage> {@Overrideprotected void channelRead0(ChannelHandlerContext channelHandlerContext, MyMessage message) {System.out.printf(message.getContent().toString());}
}

 自定义协议部分:

自定义编码:

MyEncoder.java

package zmc.com.MMessage;import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;public class MyEncoder extends MessageToByteEncoder<MyMessage> {@Overrideprotected void encode(ChannelHandlerContext channelHandlerContext, MyMessage myMessage, ByteBuf byteBuf) throws Exception {// 魔数byteBuf.writeShort(www.PACKAGE_MAGIC_NUM);// 指令类型byteBuf.writeByte(myMessage.getType().type());// 消息长度和数据内容final Object content = myMessage.getContent();if (content == null) {byteBuf.writeInt(0);} else {ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(content);byte[] bytes = bos.toByteArray();byteBuf.writeInt(bytes.length);byteBuf.writeBytes(bytes);}}
}

自定义解码:

MyDecoder.java

package zmc.com.MMessage;import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.util.List;public class MyDecoder extends ByteToMessageDecoder {@Overrideprotected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> messages) throws Exception {final int magic = byteBuf.readShort();if (magic != www.PACKAGE_MAGIC_NUM) {System.out.println(":"+ magic);}final byte opType = byteBuf.readByte();final zzz type = zzz.getOpType(opType);if (type == null) {System.out.println(":"+ opType);return;}MyMessage msg = new MyMessage();msg.setType(type);int length = byteBuf.readInt();msg.setContentLength(length);if(length > 0){byte[] contents = new byte[length];byteBuf.readBytes(contents,0, length);ByteArrayInputStream bis=new ByteArrayInputStream(contents);ObjectInputStream ois=new ObjectInputStream(bis);msg.setContent(ois.readObject());}messages.add(msg);}
}

 Message:

MyMessage.java 

package zmc.com.MMessage;
import zmc.com.MMessage.zzz;
import zmc.com.MMessage.MyMessage;
import lombok.Data;
@Data
public class MyMessage {private zzz type;private int contentLength;private Object content;public static MyMessage PingMessage() {MyMessage m = new MyMessage();m.setType(zzz.PING);return m;}public static MyMessage PongMessage() {MyMessage m = new MyMessage();m.setType(zzz.PONG);return m;}public static MyMessage StringMessage(String txt) {MyMessage m = new MyMessage();m.setType(zzz.DATA);m.setContent(txt);return m;}public zzz getType() {return type;}public void setType(zzz type) {this.type = type;}public int getContentLength() {return contentLength;}public void setContentLength(int contentLength) {this.contentLength = contentLength;}public Object getContent() {return content;}public void setContent(Object content) {this.content = content;}
}

www.java 

package zmc.com.MMessage;public interface www {short PACKAGE_MAGIC_NUM = 2021;int PACKAGE_MAX_SIZE = 50 * 1024 * 1024;}

zzz .java

package zmc.com.MMessage;public enum zzz {PING((byte)0, "666"),PONG((byte)1, "667"),DATA((byte)2, "668");private byte code;private String remark;zzz(byte code, String remark) {this.code = code;this.remark = remark;}public byte type() {return this.code;}public static zzz getOpType(byte type) {for (zzz value : values()) {if (value.type() == type) {return value;}}return null;}
}

运行结果: 

服务端:

 

 客户端1:

 客户端2:

 


http://chatgpt.dhexx.cn/article/C8WPlBV9.shtml

相关文章

netty框架的学习

netty框架的学习 1.netty环境的搭建2.netty的特点2.1什么是netty2.2为什么要使用netty3.netty框架的搭建3.1创建一个maven项目3.2导入依赖3.3搭建框架 之前几天的话开始稍微熟悉了一点maven和Springboot框架&#xff0c;从今天开始要正式的开始学习netty框架了。 1.netty环境的…

Netty框架之责任链模式及其应用

Netty框架之概述及基本组件介绍 Reactor网络编程模型解析 前言 在上篇博客介绍完netty框架的基本组件介绍和概述&#xff0c;也跟着代码看了下NioEventLoopGroup的启动过程&#xff0c;以及基于Reactor线程模型的解析&#xff0c;它是开发Netty的核心思想&#xff0c;也是整…

【初识Netty使用Netty实现简单的客户端与服务端的通信操作Netty框架中一些重要的类以及方法的解析】

一.Netty是什么&#xff1f; Netty 由 Trustin Lee(韩国&#xff0c;Line 公司)2004 年开发 本质&#xff1a;网络应用程序框架 实现&#xff1a;异步、事件驱动 特性&#xff1a;高性能、可维护、快速开发 用途&#xff1a;开发服务器和客户端 Netty的性能很高&#xff0…

Netty框架实现TCP/IP通信

项目中需要使用到TCP/IP协议完成数据的发送与接收。如果只是用以前写的简单的socket套接字方法&#xff0c;每次接收发送消息都会创建新的socket再关闭socket&#xff0c;造成资源浪费。于是使用netty框架完成java网络通信。 Netty框架的内容很多&#xff0c;这里只是代码…

在SpringBoot中整合使用Netty框架

Netty是一个非常优秀的Socket框架。如果需要在SpringBoot开发的app中&#xff0c;提供Socket服务&#xff0c;那么Netty是不错的选择。 Netty与SpringBoot的整合&#xff0c;我想无非就是要整合几个地方 让netty跟springboot生命周期保持一致&#xff0c;同生共死让netty能用…

Netty框架介绍及实战

Netty框架模型 NIO 的类库和API繁杂&#xff0c;使用麻烦&#xff1a;需要熟练掌握Selector、ServerSocket、ChannelSocketChannel、 ByteBuffer等。开发工作量和难度都非常大&#xff1a; 例如客户端面临断连重连、 网络闪断、心跳处理、半包读写、 网络拥塞和异常流的处理等…

Netty框架使用

前言 首先在使用Netty框架的时候需要了解Netty是一个什么东西。 Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具&#xff0c;用以快速开发高性能、高可靠性的网络服务器和客户端程序。也就是说&#xff0c;Netty 是一个基于NIO的…

Netty框架简介

Netty框架介绍 早已听说Netty牛逼了&#xff0c;最近有时间学习学习&#xff0c;官网地址&#xff1a;https://netty.io/&#xff0c;Java系的多种服务器/大数据框架&#xff0c;都离不开Netty做出的贡献&#xff0c;例如dubbo&#xff0c;elasticsearch等等&#xff0c;采用的…

netty框架android,隻需五步,即可基於Netty框架實現Android內網推送功能。

隻需五步,即可基於Netty框架實現Android內網推送功能。 一、先引入依賴,客戶端和服務端用的都是同一個依賴netty-all。 Android Studio中Gradle配置: compile io.netty:netty-all:5.0.0.Alpha2 IDEA中Maven配置: io.netty netty-all 5.0.0.Alpha2 二、創建消息模塊包。 目前…

Netty框架之Selector轮询器

Selector的原理详解 1.传统多线程网络通信的服务器设计2.线程池版网络通信的服务器设计Selector版网络通信的服务器设计 说到Selector的作用&#xff0c;我们不得不引入 多线程网络通信的设计 1.传统多线程网络通信的服务器设计 服务器每建立一个客户端连接Socket&#xff0c;…

netty框架学习及springboot整合集成

netty框架学习及springboot整合集成 1. Netty基本概念2. Netty框架2.1 Netty框架结构2.1 Netty NIO2.2 Reactor线程模型 3. Springboot集成netty3.1 引入jar包依赖3.2 服务端3.3 客户端 4. 参考资料 从很久以前就接触到netty&#xff0c;也在几个项目中使用netty进行网络通讯对…

Netty框架介绍

Netty框架介绍 一、netty&#xff08;通讯框架&#xff09;介紹 1、什么是netty Netty是一个基于Java NIO类库的异步通讯框架&#xff0c;他的架构特点是&#xff1a;异步非阻塞、基于事件驱动、高性能、高可靠和高定制行。 2、netty应用场景 rpc远程调用框架dubbo底层就是通…

Netty框架简述

Netty是什么&#xff1f; Netty 是一个广泛使用的 Java 网络编程框架&#xff0c;Netty提供异步的、事件驱动的网络应用程序框架和工具&#xff0c;用以快速开发高性能、高可靠性的网络服务器和客户端程序。Netty 的内部实现时很复杂的&#xff0c;但是 Netty 提供了简单易用的…

Netty框架的基本使用

Netty概述 为什么使用Netty 前面了解过的NIO模型&#xff0c;它有可靠性高、吞吐量高的优点&#xff0c;但也存在编程复杂的问题&#xff0c;我们要掌握大量的API&#xff0c;如&#xff1a;各种Channel、Buffer、Selector&#xff0c;还要编程处理特殊情况&#xff0c;如&am…

初识Netty框架

总体概述 Netty作为一款网络通信框架&#xff0c;底层封装了NIO。我们在使用Netty时&#xff0c;无需再关注NIO细节。下图为Netty处理流程图&#xff1a; 应用程序中使用Netty作为网络通信框架后&#xff0c;会形成一条PipeLine链&#xff0c;PipeLine链上有一个一个的事件处…

【java网络编程】netty框架

一、简介 netty是一个高性能、异步事件驱动的NIO框架&#xff0c;它基于Java Nio提供的API实现&#xff0c;提供了对TCP、UDP和文件传输的支持。 二、Reactor模型 Reactor是一种并发处理客户端请求响应的事件驱动模型。服务端在接收到客户端请求后采用多路复用策略&#xff0…

Netty学习二:Netty整体框架

一、Netty的整体结构和源码结构 1. Core层 提供底层网络通信的通用抽象和实现&#xff0c;包括可扩展的事件模型、通用的通信API和支持零拷贝的ByteBuf等。 common模块是Netty的核心基础包&#xff0c;提供丰富的工具类&#xff0c;其他模块都需要依赖该模块。常用的包括&…

Netty框架

概述 Netty 是由 JBOSS 提供的一个 Java 开源框架。Netty 提供异步的、基于事件驱动的网络应用程序框架&#xff0c;用以快速开发高性能、高可靠性的网络 IO 程序。 Netty 是一个基于 NIO 的网络编程框架&#xff0c;使用 Netty 可以帮助你快速、简单的开发出一个网络应用&…

Netty框架基本介绍

NIO 1.概述&#xff1a;NIO全称java non-blocking IO &#xff0c;是指JDK1.4开始&#xff0c;java提供了一系列改进的输入/输出的新特性&#xff0c;被统称为NIO(即New IO )。新增了许多用于处理输入输出的类&#xff0c;这些类都被放在java.nio包及子包下&#xff0c;并且对j…

超详细Netty入门,看这篇就够了!

思维导图 前言 本文主要讲述Netty框架的一些特性以及重要组件&#xff0c;希望看完之后能对Netty框架有一个比较直观的感受&#xff0c;希望能帮助读者快速入门Netty&#xff0c;减少一些弯路。 一、Netty概述 官方的介绍&#xff1a; Netty is an asynchronous event-drive…