从零开始手写mmo游戏从框架到爆炸(三)— 服务启动接口与网络事件监听器
导航:从零开始手写mmo游戏从框架到爆炸(零)—— 导航-CSDN博客
上一章我们完成了netty服务启动的相关抽象(https://blog.csdn.net/money9sun/article/details/136025471),这一章我们再新增一个全局的服务启动类,方便后续扩展。
服务启动
新增的两个类如下:

定义一个接口IServer
public interface IServer {/*** 服务启动* @throws Exception*/void start() throws Exception;/*** 服务关闭* @throws Exception*/void stop() throws Exception;/*** 服务重启* @throws Exception*/void restart() throws Exception;}
定义实现类 BasicServer
import com.loveprogrammer.base.factory.ServerChannelFactory;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;/*** @ClassName BasicServer* @Description 网络服务启动实现* @Author admin* @Date 2024/2/4 16:25* @Version 1.0*/
public class BasicServer implements IServer{Channel acceptorChannel;@Overridepublic void start() throws Exception {acceptorChannel = ServerChannelFactory.createAcceptorChannel();acceptorChannel.closeFuture().sync();}@Overridepublic void stop() throws Exception {if(acceptorChannel != null) {acceptorChannel.close().addListener(ChannelFutureListener.CLOSE);}}@Overridepublic void restart() throws Exception {stop();start();}
}
启动类修改:
// 启动类启动try {IServer server = new BasicServer();server.start();} catch (Exception e) {LOGGER.error( "服务器启动失败",e);}
网络事件监听器
创建一个类,用于监听网络的变化,创建一个接口INetworkEventListener,里面包含3个方法,onConnected/onDisconnected/onExceptionCaught。依然创建在core组件中
public interface INetworkEventListener {/*** 连接建立** @param ctx ChannelHandlerContext*/void onConnected(ChannelHandlerContext ctx);/*** 连接断开* * @param ctx ChannelHandlerContext*/void onDisconnected(ChannelHandlerContext ctx);/*** 异常发生* * @param ctx ChannelHandlerContext* * @param throwable 异常*/void onExceptionCaught(ChannelHandlerContext ctx, Throwable throwable);}
监听器实现类 NetworkListener:
package com.loveprogrammer.base.network.support;import com.loveprogrammer.base.network.listener.INetworkEventListener;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class NetworkListener implements INetworkEventListener {protected static final Logger logger = LoggerFactory.getLogger(NetworkListener.class);@Overridepublic void onConnected(ChannelHandlerContext ctx) {logger.info("建立连接");}@Overridepublic void onDisconnected(ChannelHandlerContext ctx) {logger.info("建立断开");}@Overridepublic void onExceptionCaught(ChannelHandlerContext ctx, Throwable throwable) {logger.warn("异常发生", throwable);}
}
然后我们要修改TcpServerStringInitializer
public class TcpServerStringInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast("framer",new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));pipeline.addLast("decoder", new StringDecoder());pipeline.addLast("encoder", new StringEncoder());INetworkEventListener listener = new NetworkListener();pipeline.addLast(new TcpMessageStringHandler(listener));}}
TcpMessageStringHandler.java 修改如下
package com.loveprogrammer.base.network.channel.tcp.str;import com.loveprogrammer.base.network.listener.INetworkEventListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @ClassName TcpMessageStringHandler* @Description tcp消息处理类* @Author admin* @Date 2024/2/4 15:16* @Version 1.0*/
public class TcpMessageStringHandler extends SimpleChannelInboundHandler<String> {private static final Logger logger = LoggerFactory.getLogger(TcpMessageStringHandler.class);private final INetworkEventListener listener;public TcpMessageStringHandler(INetworkEventListener listener) {this.listener = listener;}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) {listener.onExceptionCaught(ctx,throwable);}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {super.channelRead(ctx, msg);}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) {logger.info("数据内容:data=" + msg);String result = "我是服务器,我收到了你的信息:" + msg;result += "\r\n";ctx.writeAndFlush(result);}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {listener.onConnected(ctx);}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {listener.onDisconnected(ctx);}
}
上一章:
从零开始手写mmo游戏从框架到爆炸(二)— 核心组件抽离与工厂模式创建-CSDN博客
下一章:
从零开始手写mmo游戏从框架到爆炸(四)— session session-CSDN博客
全部源码详见:
gitee : eternity-online: 多人在线mmo游戏 - Gitee.com
分支:step-03
参考:
java游戏服务器开发: https://blog.csdn.net/cmqwan/category_7690685.html
相关文章:
从零开始手写mmo游戏从框架到爆炸(三)— 服务启动接口与网络事件监听器
导航:从零开始手写mmo游戏从框架到爆炸(零)—— 导航-CSDN博客 上一章我们完成了netty服务启动的相关抽象(https://blog.csdn.net/money9sun/article/details/136025471),这一章我们再新增一个全…...
git 合并多条提交记录
我要合并多条提交记录(合并前7条为一条),实现如下效果: 使用git rebase // 查看前10个commit git log -10 // 将7个commit压缩成一个commit;注意:vim编辑器 git rebase -i HEAD~4 // add已经跟踪的文件 g…...
C++多线程:this_thread 命名空间
std::this_thread 是 C 标准库中提供的一个命名空间,它包含了与当前线程相关的功能。这个命名空间提供了许多与线程操作相关的工具,使得在多线程环境中更容易进行编程。 源码类似于如下: namespace std{namespace this_thread{//...........…...
《山雨欲来-知道创宇 2023 年度 APT 威胁分析总结报告》
下载链接: https://pan.baidu.com/s/1eaIOyTk12d9mcuqDGzMYYQ?pwdzdcy 提取码: zdcy...
Qt信号和槽机制(什么是信号和槽,connect函数的形式,按钮的常用信号,QWidget的常用槽,自定义槽函数案例 点击按钮,输出文本)
一.什么是信号和槽 信号槽式Qt中的一个很重要的机制。信号槽实际上是观察者模式,当发生了感兴趣的事件,某一个操作就会被自动触发。当某个事件发生之后,比如按钮检测到自己被点击了一下,它就会发出一个信号。这种发出类似广播。如果有对象对…...
彻底弄懂mktemp命令的作用
mktemp 是一个在 Unix 和类 Unix 系统中用于创建临时文件或目录的命令行工具。它属于 GNU coreutils 套件的一部分。mktemp 的主要优点是它能够生成一个唯一的文件名,这有助于避免文件名冲突,并且可以安全地创建临时文件,因为这些文件通常只有…...
政安晨:示例演绎TensorFlow的官方指南(二){Estimator}
咱们接着演绎TensorFlow官方指南,我的这个系列的上一篇文章为: 政安晨:示例演绎TensorFlow的官方指南(一){基础知识}https://blog.csdn.net/snowdenkeke/article/details/136067030为什么要演绎官方指南,我…...
vue3:24—组件通信方式
目录 1、props 2、自定义事件 (emit) 3、mitt(任意组件的通讯) 4、v-model【封装ui组件库用的多,平时用的少。和vue2有点不同】 5、$attrs 6、$refs和$parent 7、provide和inject 8、pinia(即vue2中…...
WebGL+Three.js入门与实战——绘制水平移动的点、通过鼠标控制绘制(点击绘制、移动绘制、模拟画笔)
个人简介 👀个人主页: 前端杂货铺 🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…...
大数据环境搭建(一)-Hive
1 hive介绍 由Facebook开源的,用于解决海量结构化日志的数据统计的项目 本质上是将HQL转化为MapReduce、Tez、Spark等程序 Hive表的数据是HDFS上的目录和文件 Hive元数据 metastore,包含Hive表的数据库、表名、列、分区、表类型、表所在目录等。 根据Hive部署模…...
mac电脑上使用android studio创建flutter项目
mac电脑环境配置可以看这篇文章:https://xiaoshen.blog.csdn.net/article/details/136068650 配置玩环境之后,开始创建第一个flutter项目:点击new flutter project或者new project都可以 然后选择flutter: 并将sdk配置为解压后的…...
Excel——分类汇总
1.一级分类汇总 Q:请根据各销售地区统计销售额总数。 第一步:排序,我们需要根据销售地区汇总数据,我们就要对【销售地区】的内容进行排序。点击【销售地区】列中任意一个单元格,选择【数据】——【排序】,…...
Backtrader 文档学习- Observers - Reference
Backtrader 文档学习- Observers - Reference 1.Benchmark class backtrader.observers.Benchmark() 观察器存储策略的回报和参考资产的回报,参考资产是传递给系统的数据之一。 参数: timeframe (default: None) ,如果None,则将…...
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Radio组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Radio组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Radio组件 单选框,提供相应的用户交互选择项。 子组件 无。 接口 …...
【go】结构体切片去重
场景 自定义结构体切片,去除切片中的重复元素(所有值完全相同) 代码 // 自定义struct去重 type AssetAppIntranets struct {ID string json:"id,omitempty"AppID string json:"app_id,omitempty"IP …...
百面嵌入式专栏(面试题)C语言面试题22道
沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们将介绍C语言相关面试题 。 宏定义是在编译的哪个阶段被处理的?答案:宏定义是在编译预处理阶段被处理的。 解读:编译预处理:头文件包含、宏替换、条件编译、去除注释、添加行号。 写一个“标准”宏MIN,这个…...
Docker方式创建keepalived连接MGR集群
记录一下简单的搭建步骤以便后期查验 目录 前言步骤1. 安装环境2. 重新制作镜像3. 导入新镜像4. 创建容器 前言 假设已经搭建了MySQL8的MGR集群方式(一主两从)。 MGR本身有故障转移重新选举新的主节点功能,但是上游的应用程序需要自己手动修…...
Oracle PL/SQL Programming 第5章:Iterative Processing with Loops 读书笔记
总的目录和进度,请参见开始读 Oracle PL/SQL Programming 第6版 本章探讨 PL/SQL 的迭代控制结构(也称为循环),它允许您重复执行相同的代码。 PL/SQL 提供了三种不同类型的循环结构: 简单或无限循环FOR 循环&#x…...
C入门番外篇——C, Are you OK?
今日路上看到一个车牌,52U0K,感觉很有意思,如果做一下简单的翻译就是,“我爱你,好么?” 这样让我脑子中闪现了这样的一个画面:“一个男生追一个女生,看到女生不怎么搭理自己的样子&a…...
python-产品篇-游戏-象棋
文章目录 代码效果 代码 import pygame import time import constants from button import Button import pieces import computerclass MainGame():window NoneStart_X constants.Start_XStart_Y constants.Start_YLine_Span constants.Line_SpanMax_X Start_X 8 * Lin…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
