当前位置: 首页 > news >正文

一种棋牌网游的玩法

起因

俺是个记性不好的人,经常记不住牌,所以很少能赢。于是俺就写了个程序来记录出过的牌。

开始

因为是网游,所以就开始监听网络包。因为不需要改网络包,所以俺就选择了cap_ip。cap_ip是一个通过设置网卡混乱模式来监听网络包的源码,很容易在网上找到。

代码 U_GameCap

U_GameCap  用于游戏数据的网络包的监听和处理。

unit U_GameCap;interface
uses windows, classes, conn, cap_ip;
constmaxRecCount = 25 * 4 * 2; //一局牌的最多出牌信息数typeTGameCap = classprivateFPlayHallPort: integer;Fcap_ip: Tcap_ip;FconnList: TconnList;FMsgHandle: THandle;FMsg: UINT;FDebugPath: string;procedure CreatCap;procedure beginCap;procedure endCap;procedure freeCap;procedure OnCap(ip, proto, sourceIP, destIP, SourcePort, DestPort: string;header: pchar; header_size: integer; data: pchar; data_size: integer);procedure OnCapError(Error: string);procedure OnNewConn(sender: TObject; var conn: Tconn);procedure OnConnBuff(sender: TObject; var Buff: array of Byte; var ReceBuff_Len: integer);protectedprocedure ConnBuff(port: integer; var Buff: array of Byte; var ReceBuff_Len: integer); virtual;procedure postmsg(wParam: WPARAM; lParam: LPARAM);procedure debugfile(data: pchar; data_size: integer);publicUserID: integer;OutCardCounts: array[0..255] of Byte;OutCardCount: integer;GroundCards: array[0..52] of Byte;GroundCardCount: integer;GroundCards2: array[0..52] of Byte;GroundCardCount2: integer;maincard: Integer;chairid: Integer;constructor Create();destructor Destroy; override;procedure addCapPort(ip: string; port: Integer);procedure start(Port: Integer);procedure stop;property PlayHallPort: integer read FPlayHallPort;property MsgHandle: THandle read FMsgHandle write FMsgHandle;property Msg: UINT read FMsg write FMsg;property DebugPath: string read FDebugPath write FDebugPath;end;implementationuses SysUtils;{ TGameCap }procedure TGameCap.addCapPort(ip: string; port: Integer);
beginFconnList.addCapPort(ip, port);
end;procedure TGameCap.beginCap;
beginFconnList.clearCapPort;FconnList.clearconn;FconnList.addCapPort('', FPlayHallPort);Fcap_ip.StartCap;
end;procedure TGameCap.ConnBuff(port: integer; var Buff: array of Byte;var ReceBuff_Len: integer);
beginReceBuff_Len := 0;
end;procedure TGameCap.CreatCap;
beginFcap_ip := Tcap_ip.Create(nil);Fcap_ip.OnCap := OnCap;Fcap_ip.OnError := OnCapError;
end;constructor TGameCap.Create;
beginUserID := -1;maincard := -1;chairid := -1;OutCardCount := 0;GroundCardCount := 0;GroundCardCount2 := 0;FconnList := TconnList.Create;FconnList.OnNewConn := OnNewConn;CreatCap;end;procedure TGameCap.debugfile(data: pchar; data_size: integer);
varfn: string;ms: TMemoryStream;
beginms := TMemoryStream.Create;ms.Write(data[0], data_size);fn := DebugPath + FormatDateTime('HHNNSSzzz', now);while FileExists(fn) dofn := fn + '_';ForceDirectories(ExtractFilePath(fn));ms.SaveToFile(fn);FreeAndNil(ms);
end;destructor TGameCap.Destroy;
beginstop;freeCap;FreeAndNil(FconnList);inherited;
end;procedure TGameCap.endCap;
beginFcap_ip.StopCap;
end;procedure TGameCap.freeCap;
beginendCap;Fcap_ip.OnCap := nil;Fcap_ip.OnError := nil;FreeAndNil(Fcap_ip);
end;procedure TGameCap.OnCap(ip, proto, sourceIP, destIP, SourcePort,DestPort: string; header: pchar; header_size: integer; data: pchar;data_size: integer);
varPort: integer;
beginif data_size <= 0 thenexit;if proto <> 'TCP' thenexit;if SourcePort = '80' thenexit;if ip <> destIP thenexit;Port := StrToIntDef(SourcePort, 0);if Port = 0 thenexit;FconnList.processbuff(sourceIP, Port, data, data_size);
end;procedure TGameCap.OnCapError(Error: string);
begin
//
end;procedure TGameCap.OnConnBuff(sender: TObject; var Buff: array of Byte;var ReceBuff_Len: integer);
varport: integer;
beginport := Tconn(sender).port;ConnBuff(port, Buff, ReceBuff_Len);
end;procedure TGameCap.OnNewConn(sender: TObject; var conn: Tconn);
beginconn.OnConnBuff := OnConnBuff;
end;procedure TGameCap.postmsg(wParam: WPARAM; lParam: LPARAM);
beginPostMessage(FMsgHandle, FMsg, wParam, lParam);
end;procedure TGameCap.start(Port: Integer);
beginFPlayHallPort := Port;beginCap;
end;procedure TGameCap.stop;
beginendCap;
end;end.

数据解析 U_27w

//MainID: 101, AssID: 3为游戏房间数据包。
//变长,包头之后8个字节,前4为KindID,后4为游戏的NameID;
//之后为结构体,
//依次为4字节长度,4字节类型标识,4字节游戏类型,4字节KindID,4字节NameID,4字节RoomID,4字节在线人数,4字节每桌玩家数,4字节房间桌子数,
//4字节房间端口号,
//25字节房间IP地址(c格式字符串),
//31字节房间名称(含中文)。

type
  PNetMessageHead = ^NetMessageHead;
  NetMessageHead = packed record
    uMessageSize: Cardinal; //数据包大小
    bMainID: Cardinal; //处理主类型
    bAssistantID: Cardinal; //辅助处理类型 ID
    bHandleCode: Cardinal; //数据包处理代码
    bReserve: Cardinal; //保留字段
  end;
  PRec = ^TRec;
  TRec = packed record
    nextPerId: integer; //下家
    mainCardCount_0: integer; //主牌数量
    mainCardCount_1: integer;
    mainCardCount_2: integer;
    mainCardCount_3: integer;
    mainCardPairCount_0: byte; //主牌数量
    mainCardPairCount_1: byte;
    mainCardPairCount_2: byte;
    mainCardPairCount_3: byte;
    CardCount: byte; //牌数
    PerId: byte; //出牌人
    Cards: array[0..maxCardCount - 1] of byte; //牌
  end;

  T27w = class(TGameCap)
  private
    function willprocess(port: integer; pHead: PNetMessageHead): Boolean;
    procedure process(port: integer; bMainID: Cardinal; bAssistantID: Cardinal; data: pchar; size: integer);

    procedure setUserID(data: pchar; data_size: integer);
    procedure setPort(data: pchar; data_size: integer);

    procedure addrec(data: pchar; data_size: integer);
    procedure setground(data: pchar; data_size: integer);
    procedure setmain(data: pchar; data_size: integer);
    procedure setBegin(data: pchar; data_size: integer);
    procedure setground2(data: pchar; data_size: integer);
    procedure setChairid(data: pchar; data_size: integer);

    procedure newRound;
  protected
    procedure ConnBuff(port: integer; var Buff: array of Byte; var ReceBuff_Len: integer); override;
  public
    RecList: array[0..maxRecCount] of TRec;
    RecCount: integer;
    function ismaincard(v: Integer): boolean;
  end;

unit U_27w;interface
uses Windows, U_GameCap;
constmessage_maxLen = 1024 * 4;maxCardCount = 40; //一轮牌的最多出牌信息数wp_addrec = 1;wp_setground = 2;wp_setmain = 3;wp_setBegin = 4;wp_setground2 = 5;wp_setChairid = 6;
typePNetMessageHead = ^NetMessageHead;NetMessageHead = packed recorduMessageSize: Cardinal; //数据包大小bMainID: Cardinal; //处理主类型bAssistantID: Cardinal; //辅助处理类型 IDbHandleCode: Cardinal; //数据包处理代码bReserve: Cardinal; //保留字段end;PRec = ^TRec;TRec = packed recordnextPerId: integer; //下家mainCardCount_0: integer; //主牌数量mainCardCount_1: integer;mainCardCount_2: integer;mainCardCount_3: integer;mainCardPairCount_0: byte; //主牌数量mainCardPairCount_1: byte;mainCardPairCount_2: byte;mainCardPairCount_3: byte;CardCount: byte; //牌数PerId: byte; //出牌人Cards: array[0..maxCardCount - 1] of byte; //牌end;T27w = class(TGameCap)privatefunction willprocess(port: integer; pHead: PNetMessageHead): Boolean;procedure process(port: integer; bMainID: Cardinal; bAssistantID: Cardinal; data: pchar; size: integer);procedure setUserID(data: pchar; data_size: integer);procedure setPort(data: pchar; data_size: integer);procedure addrec(data: pchar; data_size: integer);procedure setground(data: pchar; data_size: integer);procedure setmain(data: pchar; data_size: integer);procedure setBegin(data: pchar; data_size: integer);procedure setground2(data: pchar; data_size: integer);procedure setChairid(data: pchar; data_size: integer);procedure newRound;protectedprocedure ConnBuff(port: integer; var Buff: array of Byte; var ReceBuff_Len: integer); override;publicRecList: array[0..maxRecCount] of TRec;RecCount: integer;function ismaincard(v: Integer): boolean;end;
implementation
{ T27w }
uses math, SysUtils;procedure T27w.addrec(data: pchar; data_size: integer);
varsize: integer;i: Byte;nowPRec: PRec;OldPRec: PRec;
beginsize := sizeof(TRec) - maxCardCount + PRec(data)^.CardCount;if size > data_size thenbegin//包不对;exit;end;i := PRec(data)^.PerId;if i > 3 thenbegin//包不对;exit;end;nowPRec := PRec(data);if RecCount > 0 thenbegin //校验重复牌for i := RecCount - 1 downto max(0, RecCount - 4) dobeginOldPRec := @RecList[i];if (OldPRec^.nextPerId < 0) or (OldPRec^.nextPerId > 3) then //轮 判断beginBreak;end;if (nowPRec^.nextPerId = OldPRec^.nextPerId) and (nowPRec^.PerId = OldPRec^.PerId) thenexit;end;end;Move(PRec(data)^, RecList[RecCount], size);inc(RecCount);nowPRec := @RecList[RecCount - 1];for i := 0 to nowPRec^.CardCount - 1 doinc(OutCardCounts[nowPRec^.Cards[i]]);inc(OutCardCount, nowPRec^.CardCount);postmsg(wp_addrec, RecCount - 1);
end;procedure T27w.ConnBuff(port: integer; var Buff: array of Byte;var ReceBuff_Len: integer);
varheadsize: integer;data: pchar;data_size: integer;size: Integer;
beginheadsize := sizeof(NetMessageHead);data_size := ReceBuff_Len;data := @Buff[0];while (data_size > headsize) dobeginsize := PNetMessageHead(data)^.uMessageSize;if size <= headsize thenbegininc(data, 1);dec(data_size, 1);Continue; //    size 比 包头 的 size 还小    错包end;if size > message_maxLen thenbegininc(data, 1);dec(data_size, 1);Continue; //    size 太大  错包end;with PNetMessageHead(data)^ doif (bMainID = 0) or (bAssistantID = 0) or (bReserve <> 0) thenbegininc(data, 1);dec(data_size, 1);Continue; //     错包end;//以上 是为了 判断 出第一个包//因为 有可能 是程序 可能 后开 接收到了 某个包的 后半端//所以 要找出 第一个 uMessageSize 的位置if size > data_size thenBreak; //    没收全if willprocess(port, PNetMessageHead(data)) thenbeginwith PNetMessageHead(data)^ doprocess(port, bMainID, bAssistantID, @(data[headsize]), size - headsize);inc(data, size);dec(data_size, size);Continue;end;inc(data, size); //   inc(data, 1);dec(data_size, size); //  inc(data, 1);end;if data_size <= 0 thenbeginReceBuff_Len := 0;endelsebeginif ReceBuff_Len <> data_size thenbeginMove(Buff[ReceBuff_Len - data_size], Buff[0], data_size);ReceBuff_Len := data_size;end;end;
end;function T27w.ismaincard(v: Integer): boolean;
varb: Byte;
beginResult := false;if maincard < 0 thenexit;if v div 16 = maincard thenbeginResult := true;exit;end;b := v mod 16;if (b = 1) or (b = 6) or (b = $E) or (b = $F) thenbeginResult := true;exit;end;
end;procedure T27w.newRound;
vararow, acol: integer;
beginRecCount := 0;OutCardCount := 0;GroundCardCount := 0;GroundCardCount2 := 0;maincard := -1;
//  chairid := -1;ZeroMemory(@OutCardCounts[0], length(OutCardCounts));
end;procedure T27w.process(port: integer; bMainID: Cardinal; bAssistantID: Cardinal; data: pchar; size: integer);
beginif port = PlayHallPort thenbeginif (bMainID = 100) or (bAssistantID = 5) thenbeginsetUserID(data, size);exit;end;if (bMainID = 101) or (bAssistantID = 3) thenbeginsetPort(data, size);exit;end;endelsebeginif (bMainID = 180) thencase bAssistantID of121: addrec(data, size);90: setground(data, size);81: setmain(data, size);62: setBegin(data, size);93: setground2(data, size);end;if (bMainID = 102) thencase bAssistantID of2: setChairid(data, size);end;end
end;procedure T27w.setBegin(data: pchar; data_size: integer);
beginnewRound;postmsg(wp_setBegin, 0);
end;procedure T27w.setground(data: pchar; data_size: integer);
varb: Byte;
begin
//   第一字节为庄的椅子号,第5~8字节为底牌数量,第9~16字节共8字节为底牌信息Move(data[0], b, 1);if b > 3 thenexit;Move(data[4], GroundCardCount, 4);if (GroundCardCount > 0) and (GroundCardCount <= 8) thenMove(data[8], GroundCards[0], GroundCardCount)elseGroundCardCount := 0;PostMsg(wp_setground, 0);
end;procedure T27w.setground2(data: pchar; data_size: integer);
varb: Byte;
begin
//  1~4字节,庄家椅子号;5~8字节,埋牌数量;
// 9~16字节,所埋牌信息。Move(data[4], GroundCardCount2, 4);if (GroundCardCount2 > 0) and (GroundCardCount2 <= 8) thenMove(data[8], GroundCards2[0], GroundCardCount2)elseGroundCardCount := 0;PostMsg(wp_setground2, 0);
end;procedure T27w.setmain(data: pchar; data_size: integer);
varb: byte;
begin
{MainID: 180, AssID: 81指定主牌花色数据包
第1字节,为叫花色玩家椅子号即庄的椅子号;
第2字节,为叫的花色,06,16,26,36分别代表方片、草花、红桃和黑桃。
}Move(data[1], b, 1);b := b div 16;if b <= 3 thenmaincard := belsemaincard := -1;PostMsg(wp_setmain, 0);
end;procedure T27w.setChairid(data: pchar; data_size: integer);
varb: Byte;tmp_userid: Integer;
beginif UserID <= 0 thenexit;Move(data[0], tmp_userid, 4);if tmp_userid <> UserID thenexit;Move(data[6], b, 1);if b <= 3 thenchairid := belsebegin// chairid := -1;end;PostMsg(wp_setChairid, 0);
end;procedure T27w.setPort(data: pchar; data_size: integer);
vari, k, count, idx, port: Integer;ip: string;a_size: Integer;
begin//MainID: 101, AssID: 3为游戏房间数据包。
//变长,包头之后8个字节,前4为KindID,后4为游戏的NameID;
//之后为结构体,
//依次为4字节长度,4字节类型标识,4字节游戏类型,4字节KindID,4字节NameID,4字节RoomID,4字节在线人数,4字节每桌玩家数,4字节房间桌子数,
//4字节房间端口号,
//25字节房间IP地址(c格式字符串),
//31字节房间名称(含中文)。if data_size <= 12 thenexit;move(data[8], a_size, 4);if a_size <> $B4 thenexit;count := (data_size - 8) div (a_size);for i := 0 to count - 1 dobeginidx := 8 + a_size * i + 36;Move(data[idx], port, 4);SetLength(ip, 25);Move(data[idx + 4], ip[1], 25);ip := Trim(ip);for k := 1 to length(ip) doif ip[k] = #0 thenbeginSetLength(ip, k - 1);Break;end;addCapPort(ip, port);end;
end;procedure T27w.setUserID(data: pchar; data_size: integer);
beginMove(data[0], userid, 4);
end;function T27w.willprocess(port: integer; pHead: PNetMessageHead): Boolean;
beginResult := false;if port = PlayHallPort thenbeginwith pHead^ doResult :=((bMainID = 100) or (bAssistantID = 5))or ((bMainID = 101) or (bAssistantID = 3));endelsebeginwith pHead^ doResult :=((bMainID = 180) or (bAssistantID = 121))or ((bMainID = 180) or (bAssistantID = 90))or ((bMainID = 180) or (bAssistantID = 62))or ((bMainID = 180) or (bAssistantID = 81))or ((bMainID = 180) or (bAssistantID = 62))or ((bMainID = 180) or (bAssistantID = 93))or ((bMainID = 102) or (bAssistantID = 2))end;
end;end.

如何知道数据包的定义?

答案就是“

这个网游刚好没有加密,而俺也刚好猜出来了。

中间记录了大量的网络包的日志。猜来猜去就猜出来了。

相关文章:

一种棋牌网游的玩法

起因 俺是个记性不好的人&#xff0c;经常记不住牌&#xff0c;所以很少能赢。于是俺就写了个程序来记录出过的牌。 开始 因为是网游&#xff0c;所以就开始监听网络包。因为不需要改网络包&#xff0c;所以俺就选择了cap_ip。cap_ip是一个通过设置网卡混乱模式来监听网络包…...

9.综合调试|输入不能存在空格|desc存在None|输出权值和ID|函数重名|修改文件名|权值和实际关键词出现次数(C++)

输入不能存在空格 目前输入的关键词时每隔一空格内容分别进行搜索&#xff0c;大部分时候我们都是将一串包含空格的内容直接进行搜索&#xff0c;需要将代码改进。 将cin换为fgets #include "searcher.hpp" #include <iostream> #include <cstdio> #in…...

使用SHOW PROCESSLIST和SHOW ENGINE INNODB STATUS排查mysql锁等待问题

现象&#xff1a; mysql 查某表一直不能结束&#xff0c;查别的表没有问题。已知之前刚刚alter此表想把它的一个字段长度增长&#xff0c;但是这个操作一直没有结束。现在应该怎么办? 方案: 使用 SHOW PROCESSLIST; 查看当前所有活动的SQL线程&#xff0c;找出是否有长时间…...

ElasticSearch映射分词

目录 弃用Type why 映射 查询 mapping of index 创建 index with mapping 添加 field with mapping 数据迁移 1.新建 一个 index with correct mapping 2.数据迁移 reindex data into that index 分词 POST _analyze 自定义词库 ik分词器 circuit_breaking_excep…...

JVM——堆的回收:引用计数发和可达性分析法、五种对象引用

目录 引用计数法和可达性分析法 引用计数法&#xff1a; 可达性分析算法&#xff1a; 五种对象引用 软引用&#xff1a; 弱引用&#xff1a; 引用计数法和可达性分析法 引用计数法&#xff1a; 引用计数法会为每个对象维护一个引用计数器&#xff0c;当对象被引用时加1&…...

PosgreSQL比MySQL更优秀吗?

一日&#xff0c;一群开发者对PosgreSQL是不是比MySQL更优秀进行了激烈的辩论&#xff0c;双方吵的都要打起来了 正方有以下理由&#xff1a; PostgreSQL严格遵循SQL标准规范&#xff0c;相较MySQL在语法兼容性和功能完整性方面展现出更强的体系化设计&#xff0c;尤其在事务处…...

冒险岛079 V8 整合版源码搭建教程+IDEA启动

今天教大家来部署下一款超级怀旧游戏冒险岛&#xff0c;冒险岛源码是开源的&#xff0c;但是开源的代码会有各种&#xff0c;本人进行了加工整合&#xff0c;并且用idea进行了启动测试&#xff0c;经过修改后没有任何问题。 启动截图 后端控制台 前端游戏界面 声明 冒险岛源码…...

基于Python的Flask微博话题舆情分析可视化系统

2024数据 ✅️标价源码 远程部署加 20 ✅️爬虫可用 有六月数据 ✅️修复bug不会突然打不开网页 系统稳定 系统的功能如下: 1.数据的爬取 2.用户的登录注册 3.热词统计&#xff0c;舆情统计 4.文章统计分析 5.发布地址统计 6.评论统计 7.情感分类统计 编程语言&#xff1a;py…...

ms-swift3 序列分类训练

目录 引言 一、数据集准备 二、训练/推理代码 2.1 训练 2.2 推理 三、性能验证 引言 swift 3.x支持了序列分类Command Line Parameters — swift 3.2.0.dev0 documentation 想尝试一下用多模态&#xff08;图像&#xff09;的序列分类与普通的图像分类任务有啥区别 一、…...

VSCode 实用快捷键

前文 VSCode 作为文本编辑神器, 熟练使用其快捷键更是效率翻倍, 本文介绍 VSCode 常用的实用的快捷键 实用快捷键 涉及到文本操作, 搜索定位, 多光标, 面板打开等快捷键 功能快捷键复制光标当前行 (不需要鼠标选中) Ctrl C 剪切光标当前行 (不需要鼠标选中) Ctrl X 当前行下…...

MVC模式和MVVM模式

目录 一、MVC模式和MVVM模式 1. MVC模式 2. MVVM 模式 3.在Qt中的应用示例 4.总结 二、MVC与MVVM模式的共同点和区别 1.共同点 2.区别 3.交互流程 4.总结 MVC&#xff08;Model-View-Controller&#xff09;和MVVM&#xff08;Model-View-ViewModel&#xff09;是两种…...

CSS伪类选择器全解析:让你的样式更加灵活和智能

目录 前言 一、什么是伪类选择器&#xff1f; 二、常见的伪类选择器详解 1. :hover —— 悬停状态 2. :active —— 活动状态 3. :focus —— 焦点状态 综合案例 4. :first-child —— 第一个子元素 5. :last-child —— 最后一个子元素 6. :nth-child(n) —— 按顺序选…...

【GESP】2024年12月图形化一级 -- 飞行的小猫

飞行的小猫 1. 准备工作 &#xff08;1&#xff09;删除默认小猫角色。 &#xff08;2&#xff09;添加角色Cat Flying和Clouds。 &#xff08;3&#xff09;删除默认白色背景&#xff0c;添加背景Blue Sky 2。 2. 功能实现 &#xff08;1&#xff09;点击绿旗&#xff0c…...

30填学习自制操作系统第二天

今天要干什么&#xff1f; 初步了解汇编语言使用汇编重新写个昨天的镜像文件继续开发 一: 什么是电信号&#xff1f; 电脑的处理中心是CPU&#xff0c;即“central process unit”的缩写&#xff0c;翻译成中文就是“中央处理单元”&#xff0c;顾名思义&#xff0c;他就是…...

MapReduce的工作原理及其在大数据处理中的应用

MapReduce是一种由Google提出的面向大数据并行处理的计算模型、框架和平台&#xff0c;它通过将复杂的数据处理任务分解为两个简单的阶段——Map&#xff08;映射&#xff09;和Reduce&#xff08;归约&#xff09;&#xff0c;实现了分布式并行计算&#xff0c;极大地提高了数…...

vue3.x 的provide 与 inject详细解读

在 Vue 3.x 中&#xff0c;provide 和 inject 是一对用于实现依赖注入的 API。它们允许父组件向其所有子组件&#xff08;无论嵌套多深&#xff09;传递数据或方法&#xff0c;而不需要通过 props 逐层传递。这在开发复杂组件或高阶组件时非常有用。 1. provide 的基本用法 p…...

c#中“事件-event”的经典示例与理解

在C#编程语言中&#xff0c;事件&#xff08;Event&#xff09;是一个非常重要的概念&#xff0c;它提供了一种松耦合的方式&#xff0c;让对象间能够通知彼此&#xff0c;而无需直接联系。事件的使用可以让我们的代码更加灵活、可扩展且易于维护。 事件可以视作委托的实例&…...

《第三代大语言模型Grok 3:闪亮登场》

《第三代大语言模型Grok 3:闪亮登场》 在科技飞速发展的今天,人工智能领域的每一次重大突破都如同巨石投入平静湖面,激起千层浪。当地时间 2 月 15 日,马斯克在社交平台 X 上投下了这样一颗 “巨石”,他宣布旗下人工智能公司 xAI 开发的第三代大语言模型 Grok 3,将于北京…...

rem、em、vw区别

在前端开发里&#xff0c;rem、em、vw都是用来设置元素大小的单位&#xff0c;下面就用大白话讲讲它们的区别。 参考标准不一样 rem&#xff1a;就像大家都用同一把“大尺子”来量东西&#xff0c;这把“大尺子”就是网页里根元素&#xff08;也就是 <html> 标签&#…...

最新Apache Hudi 1.0.1源码编译详细教程以及常见问题处理

1.最新Apache Hudi 1.0.1源码编译 2.Flink、Spark、Hive集成Hudi 1.0.1 3.flink streaming写入hudi 目录 1. 版本介绍 2. 安装maven 2.1. 下载maven 2.2. 设置环境变量 2.3. 添加Maven镜像 3. 编译hudi 3.1. 下载hudi源码 3.2. 修改hudi源码 3.3. 修改hudi-1.0.1/po…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...