Netty初体验,聊天室03(项目核心)

Netty :Netty介绍 & 实现简易多人聊天室 Netty :Netty介绍 & 实现简易多人聊天室 博主在去年二月份就介绍了Java原生网络编程API,并用它们实现了多种I/O模型的简易多人聊天室: Java网络编程-Socket编程初涉一(简易客户端-服务器) Java网络编程-Socket编程初涉二(基于BIO模型的简易多人聊天室) Java网络编程-Socket编程初涉三(伪异步I/O模型的简易多人聊天室) Java网络编程-Socket编程初涉四(NIO模型的简易多人聊天室) Java网络编程-Socket编程初涉五 阅读详情

本文主要介绍5块内容,同样也是本项目的核心代码。

1、服务端项目开发

2、客户端项目开发

3、客户端与服务端心跳机制

4、用户Session的管理

5、群组的Session的管理

开始上代码

1、服务端的开发

@Slf4j
public class ChatServer {

    public static void main(String[] args) {
        LoginRequestMessageHandler loginRequestMessageHandler = new LoginRequestMessageHandler();
        ProcotolFrameDecoder procotolFrameDecoder = new ProcotolFrameDecoder();
        MessageCodecSharable messageCodec = new MessageCodecSharable();
        ChatRequestMessageHandler chatRequestMessageHandler = new ChatRequestMessageHandler();
        GroupChatRequestHandler groupChatRequestHandler = new GroupChatRequestHandler();
        GroupCreateRequestHandler groupCreateRequestHandler = new GroupCreateRequestHandler();
        PingMessageHandler pingMessageHandler = new PingMessageHandler();
        int port = getPort();
        NioEventLoopGroup boss = new NioEventLoopGroup(1);
        NioEventLoopGroup worker = new NioEventLoopGroup(6);

        ServerBootstrap bootstrap = new ServerBootstrap();
        try {
            bootstrap.group(boss,worker)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(procotolFrameDecoder);
                            ch.pipeline().addLast(new LoggingHandler());
                            //自定义 协议
                            ch.pipeline().addLast(messageCodec);
                            ch.pipeline().addLast(pingMessageHandler);
                            //优化 防止死链接 占用资源
                            // 服务器端检测读频率 超过5秒没读到客户端请求,则认定客户端掉线
                            ch.pipeline().addLast(new IdleStateHandler(10,0,0));
                            // ChannelDuplexHandler 可以同时作为入站和出站处理器
               
                            });
                            //自定义其它handler
                            ch.pipeline().addLast(loginRequestMessageHandler);
                            ch.pipeline().addLast(chatRequestMessageHandler);
                            ch.pipeline().addLast(groupChatRequestHandler);
                            ch.pipeline().addLast(groupCreateRequestHandler);
                        }
                    });
            Channel channel = bootstrap.bind(8080).sync().channel();
            channel.closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            worker.shutdownGracefully();
            boss.shutdownGracefully();
        }

    }

2、客户端的开发

在接收客户端输入时,要新开一个线程,否则会阻塞。

@Slf4j
public class ChatClient {

    public static void main(String[] args) {
        int port = 8080;
        MessageCodecSharable messageCodec = new MessageCodecSharable();
        ProcotolFrameDecoder procotolFrameDecoder = new ProcotolFrameDecoder();
        ChatRequestMessageHandler chatRequestMessageHandler = new ChatRequestMessageHandler();
        // 通过判断true 或者 false 计算是否登录成功
        AtomicBoolean EXIT = new AtomicBoolean(false);
        // 让线程等待服务端返回登录结果
        CountDownLatch WAIT_FOR_LOGIN = new CountDownLatch(1);
        NioEventLoopGroup worker = new NioEventLoopGroup(6);
        Bootstrap bootstrap = new Bootstrap();
        Scanner scanner = new Scanner(System.in);
        try {
            bootstrap.group(worker)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(procotolFrameDecoder);
                            ch.pipeline().addLast(messageCodec);


                            // 客户端检测写事件
                            ch.pipeline().addLast(new IdleStateHandler(0,5,0));
                            //
                            ch.pipeline().addLast(new ChannelDuplexHandler(){
                                @Override
                                public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                                    IdleStateEvent event = (IdleStateEvent) evt;
                                    if (event.state() == IdleState.WRITER_IDLE){
                                        log.info("已经有2秒,客户端没有请求服务端了");
                                        //ctx.channel().close();
                                        ctx.writeAndFlush(new PingMessage(200,"心跳"));
                                    }
                                }
                            });
                            ch.pipeline().addLast(new LoggingHandler());
                            ch.pipeline().addLast(chatRequestMessageHandler);
                            ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                                @Override
                                public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                    new Thread(()->{
                                        System.out.println("请输入你的姓名:");
                                        String username = scanner.nextLine();
                                        System.out.println("请输入你的密码:");
                                        String password = scanner.nextLine();
                                        LoginRequestMessage login = new LoginRequestMessage(username,password);
                                        System.out.println("发送的数据:"+login);
                                        ctx.writeAndFlush(login);
                                        try {
                                            WAIT_FOR_LOGIN.await();
                                            while (true){
                                                System.out.println("欢迎进入聊天系统,请输入对应信息");
                                                System.out.println("==================================");
                                                System.out.println("send [username] [content]");
                                                System.out.println("gsend [group name] [content]");
                                                System.out.println("gcreate [group name] [m1,m2,m3...]");
                                                System.out.println("gmembers [group name]");
                                                System.out.println("gjoin [group name]");
                                                System.out.println("gquit [group name]");
                                                System.out.println("quit");
                                                System.out.println("==================================");
                                                String command ;
                                                command = scanner.nextLine();
                                                String[] result = command.split(" ");
                                                switch (result[0]){
                                                    case "send":
                                                        ctx.writeAndFlush(new ChatRequestMessage(result[2],result[1],username));
                                                        break;
                                                    case "gsend":
                                                        ctx.writeAndFlush(new GroupChatRequestMessage(username,result[1], result[2]));
                                                        break;
                                                    case "gcreate":
                                                        Set<String> userSet = Arrays.stream(result[2].split(",")).collect(Collectors.toSet());
                                                        userSet.add(username);
                                                        ctx.writeAndFlush(new GroupCreateRequestMessage(username,result[1],userSet));
                                                        break;
                                                    case "gmembers":
                                                        ctx.writeAndFlush("");
                                                        break;
                                                    case "gjoin":
                                                        ctx.writeAndFlush("");
                                                        break;
                                                    case "gquit":
                                                        ctx.writeAndFlush("");
                                                        break;
                                                    case "quit":
                                                        //退出
                                                        ctx.channel().close();
                                                        return;
                                                }
                                            }
                                        } catch (InterruptedException e){
                                            e.printStackTrace();
                                        }
                                    }).start();

                                }

                                @Override
                                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                    if (msg instanceof LoginResponse){
                                        LoginResponse loginResponse = (LoginResponse)msg;
                                        if (loginResponse.isSuccess()){
                                            EXIT.set(true);
                                            WAIT_FOR_LOGIN.countDown();
                                        }else if (!loginResponse.isSuccess()){
                                            ctx.channel().closeFuture();
                                        }
                                    }
                                    if (msg instanceof ChatResponseMessage){
                                        ChatResponseMessage message = (ChatResponseMessage) msg;
                                        if (message.isSuccess()){
                                            log.info("[聊天模块] 聊天失败,失败原因: {}",message.getReason());

                                        }else{
                                            log.info("[聊天模块] 聊天内容: {}",message.getContext());
                                        }
                                    }
                                    if (msg instanceof GroupChatResponseMessage){
                                        GroupChatResponseMessage message = (GroupChatResponseMessage) msg;
                                        if (message.isSuccess()){
                                            log.info("[群聊模块] 聊天失败,失败原因:{}",message.getReason());
                                        }else{
                                            log.info("[群聊模块] 聊天内容来自{},聊天内容{}",message.getFrom(),message.getContent());
                                        }
                                    }
                                    if (msg instanceof GroupCreateResponseMessage){
                                        GroupCreateResponseMessage message = (GroupCreateResponseMessage)msg;
                                        if (message.isSuccess() && message.getReason() != null){
                                            log.info("[群聊模块] 建群成功 群名{}",message.getReason());
                                        }
                                        if (!message.isSuccess()){
                                            log.info("[群聊模块] 建群失败 群名{}",message.getReason());
                                        }
                                        if (message.getFrom() != null){
                                            log.info("[群聊模块] 群主 {},拉你进群{}",message.getFrom(),message.getContent());
                                        }
                                    }
                                    if (msg instanceof PongMessage){
                                        PongMessage pongMessage = (PongMessage) msg;
                                    }
                                }
                                // 在连接断开时触发
                                @Override
                                public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                                    log.debug("连接已经断开,按任意键退出..");
                                    SessionFactory.getSession().unbind(ctx.channel());
                                    EXIT.set(true);
                                }

                                // 在出现异常时触发
                                @Override
                                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                    log.debug("连接已经断开,按任意键退出..{}", cause.getMessage());
                                    EXIT.set(true);
                                }
                            });
                        }
                    });
            Channel channel = bootstrap.connect("localhost", port).sync().channel();
            channel.closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            worker.shutdownGracefully();
        }
    }
}

3、服务端与客户端进行通信时,一定要确保对方是否存活。

心跳是检测对方是否在线的依据。心跳频率可以根据项目实际情况进行设定。

//客户端发起心跳请求
//
                            ch.pipeline().addLast(new ChannelDuplexHandler(){
                                @Override
                                public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                                    IdleStateEvent event = (IdleStateEvent) evt;
                                    if (event.state() == IdleState.WRITER_IDLE){
                                        log.info("已经有2秒,客户端没有请求服务端了");
                                        //ctx.channel().close();
                                        ctx.writeAndFlush(new PingMessage(200,"探活"));
                                    }
                                }
                            });

//服务端接收客户端的心跳请求,并响应
// 服务器端检测读频率 超过5秒没读到客户端请求,则认定客户端掉线
                            ch.pipeline().addLast(new IdleStateHandler(10,0,0));
                            // ChannelDuplexHandler 可以同时作为入站和出站处理器
                            ch.pipeline().addLast(new ChannelDuplexHandler(){
                                @Override
                                public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                                    IdleStateEvent event = (IdleStateEvent) evt;
                                    //触发了读空闲事件
                                    if (event.state() == IdleState.READER_IDLE){
                                        log.info("已经10秒没有读取到数据了");
                                        //ctx.channel().close();
                                    }
                                }
                            });


//响应客户端
@ChannelHandler.Sharable
public class PingMessageHandler extends SimpleChannelInboundHandler<PingMessage> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, PingMessage msg) throws Exception {
        ctx.writeAndFlush(new PongMessage(true,"OK"));
    }
}

4、Session的管理。

通过管理session,可以方便服务端随时向客户端发送响应。

public class SessionMemoryImpl implements Session{

    Map<Channel,String> channelBindUsername = new HashMap<>();
    Map<String,Channel> usernameBindChannel = new HashMap<>();

//在内存中保留channel与用户的绑定关系,以及用户与channel的绑定。
//方便在业务中调用
    @Override
    public void bind(Channel channel, String username) {
        channelBindUsername.put(channel,username);
        usernameBindChannel.put(username,channel);
    }

    @Override
    public void unbind(Channel channel) {
        String user = channelBindUsername.get(channel);
        channelBindUsername.remove(channel);
        usernameBindChannel.remove(user);
    }

    @Override
    public Object getAttribute(Channel channel, String name) {
        return null;
    }

    @Override
    public void setAttribute(Channel channel, String name, Object value) {

    }

    @Override
    public Channel getChannel(String username) {
        return usernameBindChannel.get(username);
    }
}

5、群组的Session管理,通过实现接口,自定义逻辑。

public interface GroupSession {

    //Map<String, Set<String>> GroupBindUsers = new HashMap<>();

    boolean createGroup(String groupName,Set<String> users);

    boolean cancelGroupMember(String groupName,String user);

    boolean cancelGroup(String groupName);

    List<Channel> getOnlineChannel(String groupName);

}

使用Netty搭建一个网络聊天室 功能复杂:要处理 “用户访问网页→返回 HTML”“解析 HTTP 参数”“WebSocket 握手”“消息广播” 等多环节,需分层解耦(MVC 将 “接收请求”“处理逻辑”“返回页面” 分开),否则代码会混乱。功能单一:主要是 “连接服务器 + 收发消息 + 显示 UI”,逻辑线性(用户操作→调用 Netty 发送→接收消息→更新 UI),无需处理 HTTP 请求、路由、页面跳转等复杂逻辑。- 需划分控制层(接收请求)、服务层(处理业务)、视图层(返回页面)(如客户端随时发消息,服务端随时推送广播)。 阅读详情

相关推荐

【COMSOL】将一个面上数据导出CSV或txt格式的方法

在COMSOL中参数化扫描后,把一个面上或体里的数据按照CSV或TXT格式导出的方法。

dave496206的博客 2993

用Netty制作的RPC框架

服务器端 package com.zhao.server; import com.zhao.protocol.MessageCodecSharable; import com.zhao.protocol.ProcotolFrameDecoder; import com.zhao.server.handler.RpcRequestMessageHandler; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Chann

weixin_47395433的博客 1065

在Kintex-7 FPGA上实现皮秒级时间测量:手把手教你搭建CARRY4进位链TDC(附源码与约束)

本文详细介绍了在Kintex-7 FPGA上利用CARRY4进位链实现皮秒级时间测量(TDC)的完整方案。从CARRY4的物理特性分析到硬件架构设计,再到校准方法与精度提升技巧,手把手教你构建测量精度达53ps的TDC系统,并附源码与约束文件,助力激光雷达、高能物理等精密计时应用开发。

weixin_42550052的博客 446

Netty根据自定义编解码器完成最简单的登录和验证

经过上面几个步骤,消息就形成了一个闭环,这个就是一个最简单的登录和验证的过程。最后可能会对 ch.pipeline().addLast(new ProcotolFrameDecoder());这个处理器的作用不太了解,这个就是确保我们消息的完整的处理器,再网络中,一条消息可能不是一条条完整的消息,因为有些消息很长,必须分段,或者有些消息很短单独一次发出去很浪费网络资源,就会把几条短的消息合并在一起一起发送。

qq_52072614的博客 1097

22版本Altium Designer导出生产文件的规范化操作指南

本文详细介绍了PCB设计中的Gerber文件导出流程及相关文件生成方法。主要内容包括:1)Gerber文件导出的5个关键设置步骤;2)NC钻孔文件的导出方法;3)坐标文件的生成方式;4)文件打包规范要求必须包含Gerber文件、NC钻孔文件和坐标文件;5)文件提交的两种方式(新手推荐提交原始工程文件,量产推荐仅提交Gerber文件包)。文章还特别强调了单位一致性、精度验证等注意事项,为PCB设计文件的规范输出提供了完整指导。

qq_56506325的博客 1060

ANSYS Fluent热边界条件避坑指南:为什么你的自然对流计算结果总出错?

本文深入剖析了在ANSYS Fluent中进行自然对流仿真时,导致计算结果出错或发散的核心原因与解决方案。重点解析了重力项与操作密度设置、Boussinesq与不可压缩理想气体模型的抉择、以及压力离散格式(推荐Body Force Weighted)这三大关键雷区,并结合电子机箱散热等实战案例,提供了一套稳定可靠的仿真设置流程与调试技巧。

weixin_28396629的博客 741

Netty详解第二课 Netty进阶和优化

三. Netty 进阶 1. 粘包与半包 1.1 粘包现象 服务端代码 public class HelloWorldServer { static final Logger log = LoggerFactory.getLogger(HelloWorldServer.class); void start() { NioEventLoopGroup boss = new NioEventLoopGroup(1); NioEventLoopGroup worke

fegus的博客 772

电磁兼容(EMC):一文读懂过电应力(EOS)

过电应力(EOS)是指元器件承受的电流或电压应力超过其允许的最大范围。产品的电磁兼容(EMC)失效的一种常见模型为过电应力(EOS),也是电子产品失效的最常见的情况之一。过电应力基本与半导体器件相关,EOS事件包括有:静电放电(ESD)、雷击、系统瞬态、电磁脉冲、充电等。本文将详细讨论一下产品设计中如何关注EOS设计。

linkking27的博客 6486

Netty——搭建一个聊天室(笔记)

Netty的简单使用 搭建一个聊天室 含自定义协议、编解码、连接假死处理等基本使用方式

weixin_46949627的博客 1090

Oracle EBS Tax 四国实现详解:印度、巴西、美国、阿根廷

印度:务必启用India Localization模块,不要尝试用标准EBTax模拟GST逻辑 巴西:必须配置NF-e接口,建议聘请本地税务顾问设置CFOP和NCM代码映射 美国:跨州业务强烈建议购买Vertex或Avalara服务,自建税率表维护成本极高 阿根廷:注意1:1:1架构限制,提前规划Legal Entity和OU结构

金牌架构师 261

SQL Server数据库备份与恢复

在 SQL Server 中,数据库备份与恢复是保障数据安全的核心操作。

zjw541806的博客 1877

四. Netty 优化与源码

四. 优化与源码 1. 优化 1.1 扩展序列化算法 序列化,反序列化主要用在消息正文的转换上 序列化时,需要将 Java 对象变为要传输的数据(可以是 byte[],或 json 等,最终都需要变成 byte[]) 反序列化时,需要将传入的正文数据还原成 Java 对象,便于处理 目前的代码仅支持 Java 自带的序列化,反序列化机制,核心代码如下 // 反序列化 byte[] body = new byte[bodyLength]; byteByf.readBytes(body); ObjectIn

weixin_46633487的博客 411

【100%通过率】华为OD机试真题 Python 实现【字符串重新排列】【2022.11 Q4新题】

给定一个字符串s,s包括以空格分隔的若干个单词,请对s进行如下处理后输出: 1、单词内部调整:对每个单词字母重新按字典序排序 2、单词间顺序调整: 1)统计每个单词出现的次数,并按次数降序排列 2)次数相同,按单词长度升序排列 3)次数和单词长度均相同,按字典升序排列 请输出处理后的字符串,每个单词以一个空格分隔。

MISAYAONE的博客 7982

基于Netty的WebSocket聊天室Demo

这个项目基于Netty 4.1.x、Spring Boot、Spring WebFlux,构建了一个基于WebSocket协议的多人聊天室Demo。这个项目能够帮助我们快速学习、了解Netty和WebSocket。

Spencercjh 929

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

netty系列之:文本聊天室

经过之前的系列文章,我们已经知道了netty的运行原理,还介绍了基本的netty服务搭建流程和消息处理器的写法。今天本文会给大家介绍一个更加复杂的例子,文本聊天室。

程序那些事 7430

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

java netty聊天室_基于netty搭建一个聊天室

前言上篇博文(netty实现消息中心(一)思路整理)大概说了下netty websocket消息中心的设计思路,这篇文章主要说说简化版的netty聊天室代码实现,支持群聊和点对点聊天。此demo主要说明netty实现消息推送的基本使用方法,如果需要扩充其它功能,可以基于此脚手架扩展。完整项目代码地址:netty聊天室github源码介绍1.登录页面login.png2.聊天页面index.png核...

weixin_32520565的博客 902

Netty版-简易聊天室

通过Netty实现简易聊天室

namelessmyth的专栏 1448

Netty实现简单聊天室:从协议解析到消息广播

核心知识点总结Netty处理WebSocket协议的关键HandlerChannelGroup管理所有在线连接WebSocketFrame的类型与处理方式性能优化的常见手段通过这个项目,我们不仅掌握了Netty与WebSocket的整合使用,更理解了高性能即时通讯系统的核心设计思路。建议读者尝试添加消息类型判断、用户列表同步等功能来巩固所学知识。

程序猿小白菜 1164

Netty - 一个简单的聊天室小项目

经过一段时间对Netty的学习,我们对Netty各版本以及像ProtocolBuffers等技术应用都有了不少相关的了解, 我们就用这段时间学到的只是做一个简单的聊天室的小项目来练习自己学到的技术。 做这个小项目之前我们先大致了解下我们需要用到的技术点,netty3.x/4.x/5.x、swingbuilder、protobuf。这里我们先以Netty3为例构建项目,各位可以通过git上查找Ne...

了无牵挂者忘生,心有所爱者忘死 8640

Netty 群聊私聊聊天室

Netty实现简易聊天室 文章目录Netty实现简易聊天室1.协议定制1.1协议格式:1.2编解码器:2.黏包半包问题3.封装消息3.1Message3.2AbstractResponseMessage3.3其他消息4.处理连接断开5.实现会话6.具体业务的实现6.1单对单聊天6.2客户端退出7.假死与心跳8.核心代码 在Netty 的学习结束之后就很想去实现一个简单的聊天室,在参考黑马视频之外,添加自己的理解和处理实现了一个建议的聊天室,本聊天室将实现简单的几个技术需求: 定制协议 协议格式定制 协

Jeffrey_oWang的博客 1056

基于Springboot+Netty实现Web聊天室

文章目录一、创建项目二、编写代码三、项目测试总结参考 一、创建项目 在IDEA中新建Spring项目 选择JDK版本,然后点击next 选择Spring Web 设置项目名称与位置 二、编写代码 导入jar包 下载地址:https://search.maven.org/artifact/com.google.code.gson/gson/2.8.9/jar 新建以下文件: 编写以下代码 DemoApplication.Java : package com.example.demo;

m0_59416558的博客 401

netty+springboot+vue聊天室(需要了解netty)

netty聊天室

在下是小白的博客 1244

Netty实现WebSocket聊天室

前面的文章主要以分析Netty源码为主,后面的文章以Netty实践为主。本篇文章会带大家使用Netty实现一个WebSocket聊天室。 代码已上传至Gitee:https://gitee.com/panchanghe/netty-project。 ​ 1. 前端代码 因为是基于网页的聊天室,所以HTML等文件必不可少。笔者是后端开发,前端写的确实不怎么样,大家凑合看吧,主要是学习Netty的使用哈~ ​ index.html: <!DOCTYPE html> <html lang="

程序员小潘 808

聊天室 - Netty WebSocket初试

背景 最近项目上面需要用到聊天室,在Ajax轮询和WebSocket之间考虑了下,决定还是采用WebSocket来实现这个项目。采用WebSocket实现,那么就必须进行服务器的技术选型,主要考虑的有Java(Netty/Jetty)、node.js(socket.io)、PHP(swoole/workerman)。 但是PHP语言的服务器就全部放弃了,论速度估计是比不上前面两者(没测试,但有人好...

dutong0321 -- 追寻计算机中的神灵 615

Netty从入门到网络聊天室实战

Netty从入门到网络聊天室实战 1.了解Netty Netty是由JBOSS提供的一个java开源框架,现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。 也就是说,Netty 是一个基于NIO的客户、服务器端的编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发

零栀 279

netty玩转irving聊天室(android整合netty客户端+springboot整合netty服务端),附源码

什么是Netty? Netty是一个异步事件驱动的网络应用程序框架 用于快速开发可维护的高性能协议服务器和客户端。 Netty优势: 使用简单:封装了 NIO 的很多细节,使用更简单。 功能强大:预置了多种编解码功能,支持多种主流协议。 定制能力强:可以通过 ChannelHandler 对通信框架进行灵活地扩展。 性能高:通过与其他业界主流的 NIO 框架对比,Netty 的综合性能最优。 稳定:Netty 修复了已经发现的所有 NIO 的 bug,让开发人员可以专注于业务本身。 社区.

LuoJun的博客 3895
上一篇: Netty初体验,聊天室02
下一篇: SQLServer 运行过程中突然宕机了,正在恢复
工作这么多年,学会了内卷
博客等级 码龄7年 156粉丝 21原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

工作这么多年,学会了内卷

共同加油,继续努力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值