im-system学习

文章目录

    • LimServer
    • LimServer
    • snakeyaml
      • 依赖
      • 使用
      • 配置类
      • 配置文件
    • 私有协议解码
      • MessageDecoder
      • ByteBufToMessageUtils

这个很全: IM即时通讯系统[SpringBoot+Netty]——梳理(总)

IO线程模型

Redis 分布式客户端 Redisson 分布式锁快速入门

LimServer

public class LimServer {private final static Logger logger = LoggerFactory.getLogger(LimServer.class);BootstrapConfig.TcpConfig config;EventLoopGroup mainGroup;EventLoopGroup subGroup;ServerBootstrap server;public LimServer(BootstrapConfig.TcpConfig config) {this.config = config;mainGroup = new NioEventLoopGroup(config.getBossThreadSize());subGroup = new NioEventLoopGroup(config.getWorkThreadSize());server = new ServerBootstrap();server.group(mainGroup,subGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 10240) // 服务端可连接队列大小.option(ChannelOption.SO_REUSEADDR, true) // 参数表示允许重复使用本地地址和端口.childOption(ChannelOption.TCP_NODELAY, true) // 是否禁用Nagle算法 简单点说是否批量发送数据 true关闭 false开启。 开启的话可以减少一定的网络开销,但影响消息实时性.childOption(ChannelOption.SO_KEEPALIVE, true) // 保活开关2h没有数据服务端会发送心跳包.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new MessageDecoder());ch.pipeline().addLast(new MessageEncoder());
//                        ch.pipeline().addLast(new IdleStateHandler(
//                                0, 0,
//                                10));ch.pipeline().addLast(new HeartBeatHandler(config.getHeartBeatTime()));ch.pipeline().addLast(new NettyServerHandler(config.getBrokerId(),config.getLogicUrl()));}});}public void start(){this.server.bind(this.config.getTcpPort());}}

LimServer

public class LimWebSocketServer {private final static Logger logger = LoggerFactory.getLogger(LimWebSocketServer.class);BootstrapConfig.TcpConfig config;EventLoopGroup mainGroup;EventLoopGroup subGroup;ServerBootstrap server;public LimWebSocketServer(BootstrapConfig.TcpConfig config) {this.config = config;mainGroup = new NioEventLoopGroup();subGroup = new NioEventLoopGroup();server = new ServerBootstrap();server.group(mainGroup, subGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 10240) // 服务端可连接队列大小.option(ChannelOption.SO_REUSEADDR, true) // 参数表示允许重复使用本地地址和端口.childOption(ChannelOption.TCP_NODELAY, true) // 是否禁用Nagle算法 简单点说是否批量发送数据 true关闭 false开启。 开启的话可以减少一定的网络开销,但影响消息实时性.childOption(ChannelOption.SO_KEEPALIVE, true) // 保活开关2h没有数据服务端会发送心跳包.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();// websocket 基于http协议,所以要有http编解码器pipeline.addLast("http-codec", new HttpServerCodec());// 对写大数据流的支持pipeline.addLast("http-chunked", new ChunkedWriteHandler());// 几乎在netty中的编程,都会使用到此hanlerpipeline.   addLast("aggregator", new HttpObjectAggregator(65535));/*** websocket 服务器处理的协议,用于指定给客户端连接访问的路由 : /ws* 本handler会帮你处理一些繁重的复杂的事* 会帮你处理握手动作: handshaking(close, ping, pong) ping + pong = 心跳* 对于websocket来讲,都是以frames进行传输的,不同的数据类型对应的frames也不同*/pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));pipeline.addLast(new WebSocketMessageDecoder());pipeline.addLast(new WebSocketMessageEncoder());pipeline.addLast(new NettyServerHandler(config.getBrokerId(),config.getLogicUrl()));}});}public void start(){this.server.bind(this.config.getWebSocketPort());}
}

snakeyaml

依赖

<!-- yaml -->
<dependency><groupId>org.yaml</groupId><artifactId>snakeyaml</artifactId><version>${snakeyaml.version}</version>
</dependency>

使用

    private static void start(String path){try {Yaml yaml = new Yaml();InputStream inputStream = new FileInputStream(path);BootstrapConfig bootstrapConfig = yaml.loadAs(inputStream, BootstrapConfig.class);new LimServer(bootstrapConfig.getLim()).start();new LimWebSocketServer(bootstrapConfig.getLim()).start();RedisManager.init(bootstrapConfig);MqFactory.init(bootstrapConfig.getLim().getRabbitmq());MessageReciver.init(bootstrapConfig.getLim().getBrokerId()+"");registerZK(bootstrapConfig);}catch (Exception e){e.printStackTrace();System.exit(500);}}

配置类

@Data
public class BootstrapConfig {private TcpConfig lim;@Datapublic static class TcpConfig {private Integer tcpPort;// tcp 绑定的端口号private Integer webSocketPort; // webSocket 绑定的端口号private boolean enableWebSocket; //是否启用webSocketprivate Integer bossThreadSize; // boss线程 默认=1private Integer workThreadSize; //work线程private Long heartBeatTime; //心跳超时时间 单位毫秒private Integer loginModel;/*** redis配置*/private RedisConfig redis;/*** rabbitmq配置*/private Rabbitmq rabbitmq;/*** zk配置*/private ZkConfig zkConfig;/*** brokerId*/private Integer brokerId;private String logicUrl;}@Datapublic static class ZkConfig {/*** zk连接地址*/private String zkAddr;/*** zk连接超时时间*/private Integer zkConnectTimeOut;}@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic static class RedisConfig {/*** 单机模式:single 哨兵模式:sentinel 集群模式:cluster*/private String mode;/*** 数据库*/private Integer database;/*** 密码*/private String password;/*** 超时时间*/private Integer timeout;/*** 最小空闲数*/private Integer poolMinIdle;/*** 连接超时时间(毫秒)*/private Integer poolConnTimeout;/*** 连接池大小*/private Integer poolSize;/*** redis单机配置*/private RedisSingle single;}/*** redis单机配置*/@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic static class RedisSingle {/*** 地址*/private String address;}/*** rabbitmq哨兵模式配置*/@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic static class Rabbitmq {private String host;private Integer port;private String virtualHost;private String userName;private String password;}}

配置文件

lim:tcpPort: 9000webSocketPort: 19000bossThreadSize: 1workThreadSize: 8heartBeatTime: 20000 #心跳超时时间 单位毫秒brokerId: 1000loginModel: 3logicUrl: http://127.0.0.1:8000/v1#  *                多端同步模式:1 只允许一端在线,手机/电脑/web 踢掉除了本client+imel的设备#  *                            2 允许手机/电脑的一台设备 + web在线 踢掉除了本client+imel的非web端设备#  *                            3 允许手机和电脑单设备 + web 同时在线 踢掉非本client+imel的同端设备#  *                            4 允许所有端多设备登录 不踢任何设备redis:mode: single # 单机模式:single 哨兵模式:sentinel 集群模式:clusterdatabase: 0password:timeout: 3000 # 超时时间poolMinIdle: 8 #最小空闲数poolConnTimeout: 3000 # 连接超时时间(毫秒)poolSize: 10 # 连接池大小single: #redis单机配置address: 127.0.0.1:6379rabbitmq:host: 127.0.0.1port: 5672virtualHost: /userName: guestpassword: guestzkConfig:zkAddr: 127.0.0.1:2181zkConnectTimeOut: 5000

私有协议解码

MessageDecoder

public class MessageDecoder extends ByteToMessageDecoder {@Overrideprotected void decode(ChannelHandlerContext ctx,ByteBuf in, List<Object> out) throws Exception {//请求头(指令// 版本// clientType// 消息解析类型// appId// imei长度// bodylen)+ imei号 + 请求体if(in.readableBytes() < 28){return;}Message message = ByteBufToMessageUtils.transition(in);if(message == null){return;}out.add(message);}
}

ByteBufToMessageUtils

/*** @author: Chackylee* @description: 将ByteBuf转化为Message实体,根据私有协议转换*               私有协议规则,*               4位表示Command表示消息的开始,*               4位表示version*               4位表示clientType*               4位表示messageType*               4位表示appId*               4位表示imei长度*               imei*               4位表示数据长度*               data*               后续将解码方式加到数据头根据不同的解码方式解码,如pb,json,现在用json字符串* @version: 1.0*/
public class ByteBufToMessageUtils {public static Message transition(ByteBuf in){/** 获取command*/int command = in.readInt();/** 获取version*/int version = in.readInt();/** 获取clientType*/int clientType = in.readInt();/** 获取clientType*/int messageType = in.readInt();/** 获取appId*/int appId = in.readInt();/** 获取imeiLength*/int imeiLength = in.readInt();/** 获取bodyLen*/int bodyLen = in.readInt();if(in.readableBytes() < bodyLen + imeiLength){in.resetReaderIndex();return null;}byte [] imeiData = new byte[imeiLength];in.readBytes(imeiData);String imei = new String(imeiData);byte [] bodyData = new byte[bodyLen];in.readBytes(bodyData);MessageHeader messageHeader = new MessageHeader();messageHeader.setAppId(appId);messageHeader.setClientType(clientType);messageHeader.setCommand(command);messageHeader.setLength(bodyLen);messageHeader.setVersion(version);messageHeader.setMessageType(messageType);messageHeader.setImei(imei);Message message = new Message();message.setMessageHeader(messageHeader);if(messageType == 0x0){String body = new String(bodyData);JSONObject parse = (JSONObject) JSONObject.parse(body);message.setMessagePack(parse);}in.markReaderIndex();return message;}}

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

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

相关文章

【Week Y2】使用自己的数据集训练YOLO-v5s

Y2-使用自己的数据集训练YOLO-v5s 零、遇到的问题汇总&#xff08;1&#xff09;遇到git的import error&#xff08;2&#xff09;Error&#xff1a;Dataset not found&#xff08;3&#xff09;Error&#xff1a;删除中文后&#xff0c;训练图片路径不存在 一、.xml文件里保存…

框架篇常见面试题

1、Spring框架的单例bean是线程安全的吗&#xff1f; 2、什么是AOP&#xff1f; 3、Spring的事务是如何实现的&#xff1f; 4、Spring事务失效的场景 5、SpringBean的声明周期 6、Spring的循环依赖 7、SpringMVC的执行流程 8、SpringBoot自动配置原理 9、Spring常见注解

Java中的实用类讲解(中篇)

如果想观看更多Java内容 可上我的个人主页关注我&#xff0c;地址子逸爱编程-CSDN博客https://blog.csdn.net/a15766649633?spm1000.2115.3001.5343 使用工具 IntelliJ IDEA Community Edition 2023.1.4 使用语言 Java8 代码能力快速提升小方法&#xff0c;看完代码自己敲…

AV1:帧内预测(一)

​VP9支持10种帧内预测模式&#xff0c;包括8种角度模式和非角度模式DC、TM(True Motion)模式&#xff0c;AV1在其基础上进一步扩展&#xff0c;AV1帧内预测角度模式更细化&#xff0c;同时新增了部分非角度模式。 扩展的角度模式 AV1在VP9角度模式的基础上进一步扩展&#xf…

CSharp的lambda表达式匿名类扩展方法

c#的lamba表达式 之前已经写过一些关于委托还有事件的文章&#xff0c;今天就来介绍一下lambda表达式。 首先定义需要的函数以及委托 { public delegate void DoNothingDelegate(); public delegate void StudyDelegate(int id, string name);private void DoNothing() {Cons…

P1678 烦恼的高考志愿(二分查找)

题目描述 现有 m 所学校&#xff0c;每所学校预计分数线是 ai​。有 n 位学生&#xff0c;估分分别为 bi​。 根据 n 位学生的估分情况&#xff0c;分别给每位学生推荐一所学校&#xff0c;要求学校的预计分数线和学生的估分相差最小&#xff08;可高可低&#xff0c;毕竟是估分…

蓝桥杯day3刷题日记--P9420 [蓝桥杯 2023 国 B] 子 2023 / 双子数

2023 思路&#xff1a;首先先用to_string把数字变成字符串&#xff08;ps&#xff1a;在Dev c里用不了&#xff09;&#xff0c;用数组dp&#xff0c;用dp【0】记录2的数量&#xff0c;dp【1】记录20的数量&#xff0c;dp【2】记录202的数量&#xff0c;dp【3】记录2023的数量…

蓝桥杯--完全二叉树

import java.util.Scanner;import static java.lang.Math.log;public class top9 {//求树的每一层的和public static void main(String [] args){Scanner scannernew Scanner(System.in);int nscanner.nextInt();int [] arrnew int[n];for(int i0;i<n;i){arr[i]scanner.next…

Android Studio实现内容丰富的安卓志愿者平台

获取源码请点击文章末尾QQ名片联系&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动 项目编号122 1.开发环境android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看公告 3.查看岗位 4.浏览新闻&#xff0c; 5.个人中心…

1、Java虚拟机学习-类的生命周期-加载阶段-以及怎样查看方法区中的对象和堆中对象的关联以及静态变量存在什么地方

类的生命周期 其中连接又可以分为3个小阶段 一、加载阶段 1、加载阶段第一步是类加载器根据类的全限定名通过不同的渠道以二进制流的方式获取字节码信息。 渠道: 2、类加载器在加载完类之后&#xff0c;Java虚拟机会将字节码中的信息保存在内存的方法区中。 方法区是虚拟…

使用Vscode连接云进行前端开发

使用Vscode连接云进行前端开发 1、ssh连接腾讯云 本人使用的是腾讯云。 然后vscode,用最新版&#xff0c;插件选择remote ssh&#xff0c;或者remote xxx下载过来。 然后点击远程资源管理器&#xff0c;选择SSH通道 然后输入命令如下。 ssh rootip然后输入密码 腾讯云应该…

Source Insight使用-添加新的文件类型

目录 遇到的问题解决方法结果 遇到的问题 在Source Insight中我们通常查看.c和.h文件&#xff0c;当使用其查看.java 或者.hal等类型文件时&#xff0c;发现找不到 解决方法 以添加.hal文件为例: 选择Options 下面的File Type Options… 选项。 点击左侧的 “C/C Source F…

哈尔滨工业大学 《材料物理》 笔记-3

原内容请参考哈尔滨工业大学何飞教授&#xff1a;https://www.bilibili.com/video/BV18b4y1Y7wd/?p12&spm_id_frompageDriver&vd_source61654d4a6e8d7941436149dd99026962 或《材料物理性能及其在材料研究中的应用》&#xff08;哈尔滨工业大学出版社&#xff09; 量…

YOLOv9改进策略:卷积魔改 | 分布移位卷积(DSConv),提高卷积层的内存效率和速度

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文改进内容&#xff1a; YOLOv9如何魔改卷积进一步提升检测精度&#xff1f;提出了一种卷积的变体&#xff0c;称为DSConv&#xff08;分布偏移卷积&#xff09;&#xff0c;其可以容易地替换进标准神经网络体系结构并且实现较低的存…

针对BSV区块链新推出的网络访问规则NAR和警报系统AS的解释与问答

​​发表时间&#xff1a;2024年2月22日 BSV区块链社区团队最近开设了一个Twitter&#xff08;X&#xff09;话题空间&#xff0c;讨论BSV区块链协会最新推出的网络访问规则和警报系统的相关问题。 本次讨论由BSV区块链社区负责人Brett Banfe主持&#xff0c;以便社区成员更好…

vivado 物理优化约束、交互式物理优化

物理优化约束 Vivado Design Suite在物理优化过程中尊重DONT_TOUCH特性。它不在具有这些属性的网络或小区上执行物理优化。要加快网络选择过程中&#xff0c;具有DONT_TOUCH属性的网络经过预过滤&#xff0c;不被考虑用于物理优化。此外&#xff0c;还遵守Pblock分配&#xff…

母亲的奶牛(bfs)

农夫约翰有三个容量分别为 A , B , C A,B,C A,B,C 升的挤奶桶。 最开始桶 A A A 和桶 B B B 都是空的&#xff0c;而桶 C C C 里装满了牛奶。 有时&#xff0c;约翰会将牛奶从一个桶倒到另一个桶中&#xff0c;直到被倒入牛奶的桶满了或者倒出牛奶的桶空了为止。 这一过…

Linux常用命令之搜索查找类

1.1find查找文件或目录 1&#xff09;基本语法 find [搜索范围] [ 选项] find -name&#xff1a;按照名字查找 find -user&#xff1a;按用户相关查找 find -size&#xff1a;按照文件大小查找 1.2locate快速定位文件路径 经验技巧&#xff1a;由于locate指令基于数据库进行…

HP Pavilion Laptop 15-eg2xxx原厂Win11系统预装oem系统包

惠普星15青春版笔记本原装出厂Windows11系统镜像下载&#xff0c;恢复出厂开箱状态 链接&#xff1a;https://pan.baidu.com/s/1f4hjwWX0CMDykb_8YXSf-w?pwd0aja 提取码&#xff1a;0aja 适用型号&#xff1a; 15-eg0010TU、15-eg0011TU、15-eg0008TX、15-eg0009TX 15-eg…

YOLOv8-pose自定义关键点推理封装

使用场景:自己定义的关键点比如说做了耳蜗检测有13个关键点(就是原来的pose点数了)可以单独修改每个关键点的颜色以及Label的颜色。 代码: import cv2 from ultralytics import YOLO import torch import numpy as npclass PoseDetector:def __init__(self, model_path):s…