深入解析B站androidApp接口:从bilibili.api.ticket.v1.Ticket/GetTicket到SendMsg的技术分析
前言
最近一段时间,我对B站的App接口进行了深入分析,特别是关注了认证机制和私信功能的实现。通过逆向工程和网络抓包,发现了B站移动端API的底层工作原理,包括设备标识生成机制、认证流程和消息传输协议。本文将分享这些研究成果,希望能对API安全设计和防护提供一些思考。
B站接口的基本架构
B站的移动端API采用了gRPC作为主要通信协议,这与普通的REST API有较大区别。gRPC使用Protocol Buffers(protobuf)进行数据序列化,具有更高的效率和更严格的类型检查。
gRPC请求结构
B站的API请求通常包含以下几个关键部分:
[压缩标志(1字节)][消息长度(4字节)][Protobuf消息体]
- 压缩标志:通常是0(不压缩)或1(gzip压缩)
- 消息长度:大端序的4字节整数,表示消息体的长度
- 消息体:使用protobuf编码的实际数据
例如,一个典型的请求可能是:
00 00 00 00 52 0A 2A 08 88 F3 EC 8A 01 10 01 18 E4 C7 A0 85 01 20 E9 8D FF E7 07 28 01 32 0F 7B 22 63 6F 6E 74 65 6E 74 22 3A 22 32 22 7D 80 01 01 2A 24 65 65 62 35 35 63 38 37 2D 66 32 36 34 2D 34 39 64 33 2D 61 61 39 62 2D 63 37 36 34 39 66 36 31 39 34 33 38
其中:
00
- 不使用压缩00 00 00 52
- 消息长度为82字节- 剩余部分 - protobuf编码的消息体
设备标识机制深度解析
BUVID生成机制
BUVID (Bilibili Unique Video ID) 是B站用来唯一标识设备的关键值,其生成过程如下:
def generate_buvid(device_id, buvid_type):"""生成BUVID (B站设备唯一标识)参数:device_id: 设备ID (根据buvid_type的不同可以是AndroidID、MAC等)buvid_type: BUVID类型 (XX代表Android ID, XY代表MAC地址)"""# 预处理device_idif buvid_type == BUVIDType.MAC:device_id = device_id.replace(":", "")# 计算device_id的MD5值并转为大写id_md5 = hashlib.md5(device_id.encode('utf-8')).hexdigest().upper()# ..............(敏感信息脱敏处理)# 最终BUVID: 类型前缀 + ID_E + MD5buvid = buvid_type + id_e + id_md5return buvid
BUVID的格式为:XX/XY
+ 3位特征码
+ 32位MD5
,共37位字符。
设备指纹(fp_local)生成与BUVID的关系
设备指纹(fp_local)与BUVID密切相关,通常用于二次验证设备身份。fp_local的生成依赖于BUVID,同时也考虑了设备型号和无线电版本信息:
def generate_fp(buvid, device_model, device_radio):"""根据BUVID生成设备指纹"""# 1. 构建基础字符串并计算MD5base_str = buvid + device_model + device_radiomd5_hex = hashlib.md5(base_str.encode('utf-8')).hexdigest()# 2. 添加时间戳time_str = datetime.now().strftime("%Y%m%d%H%M%S")# 3. 添加随机字符串(16位十六进制)random_hex = ''.join(random.choice('0123456789abcdef') for _ in range(16))# 4. 合并所有部分fp_base = md5_hex + time_str + random_hex# 5. 计算校验和,这里是关键部分。所以随机生成并不能通过验证calculate_checksum就不公布了checksum = calculate_checksum(fp_base)# 6. 返回完整指纹return fp_base + checksum
关键点:
- fp_local的首32位是由BUVID、设备型号和无线电版本共同决定的MD5值
- 接下来14位是生成时的时间戳
- 再加上16位随机数据
- 最后2位是校验和
BUVID与fp_local的关系验证:
def verify_fp(buvid, fp, device_model, device_radio):"""验证FP是否与BUVID匹配"""# 1. 提取FP中的MD5部分(前32个字符)fp_md5 = fp[:32]# 2. 计算预期的MD5base_str = buvid + device_model + device_radioexpected_md5 = hashlib.md5(base_str.encode('utf-8')).hexdigest()# 3. 验证MD5部分是否匹配if fp_md5 != expected_md5:return False# 4. 验证校验和fp_base = fp[:-2]expected_checksum = calculate_checksum(fp_base)actual_checksum = fp[-2:]# 5. 返回校验和是否匹配return expected_checksum == actual_checksum
这种设计确保了:
- 设备更换后无法保持相同的指纹
- 服务器可以验证设备指纹的真实性
- 可以检测设备信息的篡改
Ticket认证机制分析
JWT格式的Ticket结构
Ticket采用JWT(JSON Web Token)格式,由三部分组成:Header、Payload和Signature。
典型的B站Ticket如下:
eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDQ2NTYxNjcsImlhdCI6MTc0NDYyNzA2NywiYnV2aWQiOiJYVUY4MjRFRkQ3NjUyNTE5NzhCOEIyNzlEMDYyODNFQkQ1OTZFIn0.flJFBus6TltpIlD_byS2bM0kzXyQe0o-5ndOnrtuTOc
解析后:
- Header:
{"alg":"HS256","kid":"s03","typ":"JWT"}
- Payload:
{"exp":1744656167,"iat":1744627067,"buvid":"XUF824EFD765251978B8B279D06283EBD596E"}
- Signature: HMAC-SHA256签名
Ticket获取请求的构造
获取Ticket的请求较为复杂,涉及多层嵌套的protobuf消息和签名计算:
def create_ticket_request(self, device_bin):"""创建Ticket请求数据"""# 创建请求数据request_data = bytearray()# 创建x-fingerprint的值fingerprint_value = self.create_fingerprint_value()# 添加字段1: context (x-fingerprint)# 添加字段1: context (x-exbadbasket)# 将两个context条目添加到请求中# 添加字段2: key_id = "ec01"# 添加字段3: sign# 压缩数据compressed_data = gzip.compress(bytes(request_data))# 构造gRPC消息# ----------- 此处省略return bytes(grpc_message)
签名计算的安全性
签名计算是认证系统的核心安全机制:
def calculate_app_sign(self, device_bin, fingerprint_value, exbadbasket_value=b''):"""计算应用签名"""# 签名密钥key = b'E2lc5tgtl' # 注:此处为示例密钥,非真实值# 将base64编码的device_bin解码device_bin_data = base64.b64decode(device_bin)# 创建HMAC对象h = hmac.new(key, digestmod=hashlib.sha256)# 按特定顺序更新数据# 此处脱敏处理,省略# 获取十六进制摘要return h.hexdigest()
Protobuf消息的构造与解析
protobuf字段类型
protobuf编码中,每个字段都由标签和值组成:
- 标签:
(field_number << 3) | wire_type
- 值:根据wire_type决定编码方式
常见的wire_type:
- 0: Varint (int32, int64, bool等)
- 1: 64-bit (fixed64, double等)
- 2: Length-delimited (string, bytes, embedded messages等)
- 5: 32-bit (fixed32, float等)
手动构造protobuf消息
没有.proto定义文件时,我们需要手动构造protobuf消息,当然你也可以用现成的库去处理:
def append_tag(self, buf, field_number, wire_type):"""添加字段标签"""tag = (field_number << 3) | wire_typeself.append_varint(buf, tag)def append_varint(self, buf, value):"""添加varint类型的值"""while value >= 0x80:buf.append((value & 0x7f) | 0x80)value >>= 7buf.append(value & 0x7f)def append_string(self, buf, value):"""添加字符串类型字段"""encoded = value.encode('utf-8')self.append_varint(buf, len(encoded)) # 长度前缀buf.extend(encoded) # 字符串内容
解析protobuf消息
从二进制数据解析protobuf消息也很关键:
def parse_protobuf(data):"""解析protobuf格式数据"""result = {}try:offset = 0while offset < len(data):# 获取字段编号和类型field_and_type = data[offset]field_num = field_and_type >> 3wire_type = field_and_type & 0x07offset += 1# 基于wire_type处理不同类型的数据if wire_type == 0: # Varintvalue = 0shift = 0while True:b = data[offset]offset += 1value |= ((b & 0x7f) << shift)if not (b & 0x80):breakshift += 7result[str(field_num)] = valueelif wire_type == 2: # Length-delimitedlength = 0shift = 0while True:b = data[offset]offset += 1length |= ((b & 0x7f) << shift)if not (b & 0x80):breakshift += 7# 尝试解析为字符串、JSON或嵌套消息try:string_value = data[offset:offset+length].decode('utf-8')if string_value.startswith('{') and string_value.endswith('}'):try:json_value = json.loads(string_value)result[str(field_num)] = string_valueexcept:result[str(field_num)] = string_valueelse:result[str(field_num)] = string_valueexcept:# 嵌套消息或二进制数据nested_result = parse_protobuf(data[offset:offset+length])if nested_result:result[str(field_num)] = nested_resultelse:result[str(field_num)] = data[offset:offset+length].hex()offset += length# 处理其他wire_type...except Exception as e:print(f"Protobuf解析错误: {e}")return result
私信发送功能详解
私信消息的protobuf结构
私信消息的protobuf结构如下:
消息 {field1: { // 内部消息field1: 接收者UID (VarInt)field2: 消息类型 (VarInt)field3: 序列号 (VarInt)field4: 设备标识 (VarInt)field5: 标志位 (VarInt)field6: 消息内容JSON (String)field16: 标志位 (VarInt)}field5: 消息ID (String)
}
构造和发送私信
def create_and_send_message(self, content, receiver_uid, message_id=None):"""构造并发送B站私信消息"""# 生成消息IDif message_id is None:message_id = str(uuid.uuid4())# 创建消息数据message_data = bytearray()# 添加内部消息inner_msg = bytearray()# 添加接收者UID# 添加消息类型# 添加序列号# 添加设备标识# 添加标志位# 添加消息内容(JSON格式)# 添加标志位self.append_tag(inner_msg, 16, 0)self.append_varint(inner_msg, 1)# 将内部消息添加到外层消息self.append_tag(message_data, 1, 2)self.append_varint(message_data, len(inner_msg))message_data.extend(inner_msg)# 添加消息IDself.append_tag(message_data, 5, 2)self.append_string(message_data, message_id)# 创建gRPC消息# 准备请求头headers = {"APP-KEY": "android64","Content-Type": "application/grpc","User-Agent": "...","buvid": self.buvid,"x-bili-device-bin": self.device_bin(),"x-bili-fawkes-req-bin": self.fawkes_req_bin(),"x-bili-locale-bin": "...","x-bili-metadata-bin": self.generate_bili_metadata(),"authorization": f"identify_v1 {self.access_key}","x-bili-ticket": self.ticket# 其他必要的头信息...}# 发送请求url = "https://app.bilibili.com/bilibili.im.interface.v1.ImInterface/SendMsg"response = requests.post(url, headers=headers, data=bytes(grpc_message))return response
解析Base64编码的错误消息
B站的错误响应常常是Base64编码的protobuf消息:
def parse_base64_protobuf(base64_str):"""解析Base64编码的protobuf数据"""try:# 补全paddingpadding = len(base64_str) % 4if padding:base64_str += '=' * (4 - padding)# 解码Base64decoded_data = base64.b64decode(base64_str)# 解析protobufreturn resultexcept Exception as e:print(f"解析Base64 protobuf数据失败: {e}")return None
例如,错误消息CAISBTIxMDI2GlAKJ3R5cGUuZ29vZ2xlYXBpcy5jb20vYmlsaWJpbGkucnBjLlN0YXR1cxIlCKKkARIf5LiN6IO957uZ6Ieq5bex5Y+R6YCB5raI5oGv5ZOmfg
解析后可能包含"不允许给自己发送消息"的提示。
技术要点分析
1. 多层认证机制
B站采用了多层认证策略:
- BUVID:设备唯一标识
- fp_local:基于BUVID的设备指纹
- Ticket:JWT格式的临时凭证
- access_key:长期授权令牌
这种多层机制增加了伪造身份的难度。
2. 签名验证
请求过程中,多处使用了HMAC签名来确保数据完整性和来源可靠性。例如:
- Ticket请求中对device_bin和fingerprint_value进行签名
- JWT格式的Ticket本身也包含签名
3. 设备指纹算法
设备指纹(fp_local)的生成算法具有以下特点:
- 基于设备特征(BUVID、型号、无线电版本)
- 包含时间戳,允许追踪指纹生成时间
- 添加校验和,验证数据完整性
- 部分随机化,防止完全预测
4. protobuf格式的优势利用
B站充分利用了protobuf的优势:
- 高效的序列化/反序列化
- 严格的类型检查
- 二进制格式难以直接分析和修改
- 版本兼容性好
5. 协议头中各个值的算法
Ascii 类
user-agent
客户端 UA, 必需.
device_model
设备 Model
device_build
设备 Build
app_ver
APP 版本号
mobi_app
APP 包类型
app_build
APP 版本号
app_build_inner
APP 版本号(内部)
x-bili-gaia-vtoken
暂时留空.
x-bili-aurora-eid
未登录留空. 必需.
x-bili-mid
用户 UID, 未登录默认为 0. 必需.
x-bili-aurora-zone
留空. 必需.
x-bili-trace-id
如 16e903399574695df75be114ff63ac64:f75be114ff63ac64:0:0. 需要算法处理. 必需.
authorization
鉴权, 登录时设定为 identify_v1 {access_key}, 未登录时无需此项.
buvid
设备唯一标识, 有自己的一套算法.
bili-http-engine
cronet
te
trailers
Binary 类
x-bili-fawkes-req-bin
设备 Fawkes 信息,加密信息,必须
x-bili-metadata-bin
使用 Metadata 生成. 加密信息,必须
x-bili-device-bin
设备信息, 加密信息,必须
x-bili-network-bin
设备网络信息, 加密信息,必须
x-bili-restriction-bin
限制信息, 加密信息,必须
x-bili-locale-bin
设备区域信息,加密信息,必须
x-bili-exps-bin
加密信息,必须
安全漏洞与防范建议
通过分析,我发现了几个潜在的安全问题及其防范措施:
1. 设备模拟防范
问题:通过分析可以伪造设备信息,包括BUVID和指纹。
防范措施:
- 增加设备特征采集,如硬件序列号、系统指纹等
- 引入设备行为特征分析,识别异常行为模式
- 实施设备绑定策略,限制账号可用设备数量
- 定期更新设备指纹算法,增加逆向难度
2. 签名密钥保护
问题:客户端存储的签名密钥可能被提取。
防范措施:
- 使用白盒加密技术保护客户端密钥
- 实施密钥分散存储和动态派生
- 定期轮换密钥
- 服务端增加额外验证,不完全依赖客户端签名
3. Protobuf结构保护
问题:通过逆向工程可以分析出protobuf结构。
防范措施:
- 混淆字段名和字段编号
- 定期更新协议结构
- 添加冗余或诱饵字段
- 对关键字段进行额外加密
4. JWT安全加固
问题:JWT可能面临重放攻击或篡改。
防范措施:
- 缩短Token有效期
- 实施Token绑定(将Token与特定会话或设备绑定)
- 使用更强的签名算法(如ES256而非HS256)
- 服务端维护已吊销Token列表
5. 请求频率限制
问题:可能出现API滥用。
防范措施:
- 实施基于账号和设备的请求频率限制
- 为敏感操作增加验证码或其他人机验证
- 监控异常请求模式并实施自动封禁
- 对同一设备的多账号操作进行关联分析
实践经验与优化方向
代码优化
在研究过程中,我发现以下编码实践更有效:
# 更清晰的protobuf构造
def create_message(receiver_id, content):msg = bytearray()# 使用辅助函数增加可读性add_varint_field(msg, 1, receiver_id)add_string_field(msg, 6, json.dumps({"content": content}))return msg
调试技巧
分析和调试protobuf消息:
def debug_protobuf(hex_data):"""将十六进制数据解析为人类可读的形式"""data = binascii.unhexlify(hex_data.replace(" ", ""))result = parse_protobuf(data)# 美化输出return json.dumps(result, indent=2, ensure_ascii=False)
结语
通过对B站App接口的深入分析,我们不仅理解了其身份验证和消息发送机制,也掌握了protobuf消息的构造和解析技术。这些知识不仅适用于B站,也可以应用到其他使用类似技术栈的应用分析中。
对于API开发者,本文揭示了现代移动应用API安全设计的多层次防护策略,以及可能的改进方向。对于研究者,则提供了一个深入理解gRPC和protobuf在实际应用中如何使用的案例。
希望本文对你了解现代移动应用的API实现有所帮助。记住,技术研究应当遵守伦理和法律边界,尊重平台和用户的权益。
本文内容仅供学习和研究使用,请勿用于任何非法或违反相关服务条款的目的。使用本文中的技术进行未授权访问或攻击行为可能违反《网络安全法》等相关法律法规,责任自负,如有需要联系作者可通过 dGcgQGludm9rZXlvdQ==
(base64decode后查看联系方式) 联系我。
相关文章:
深入解析B站androidApp接口:从bilibili.api.ticket.v1.Ticket/GetTicket到SendMsg的技术分析
前言 最近一段时间,我对B站的App接口进行了深入分析,特别是关注了认证机制和私信功能的实现。通过逆向工程和网络抓包,发现了B站移动端API的底层工作原理,包括设备标识生成机制、认证流程和消息传输协议。本文将分享这些研究成果…...
[AI ][Dify] 构建一个自动化新闻编辑助手:Dify 工作流实战指南
在内容创作行业中,自动化辅助工具已成为提升编辑效率的重要利器。本文将通过 Dify 平台,演示如何构建一个**“新闻编辑助手”**,实现从网页抓取、文本翻译、标题生成,到新闻配图的全流程自动化。 🎯 目标概览 这个工作流旨在实现如下功能: 从指定网页抓取新闻内容; 使…...
Unity中国战略调整简讯:Unity6下架 团结引擎接棒
Unity中国战略调整简讯:Unity6下架 团结引擎接棒 免费版 2025年4月9日 —— Unity中国宣布自即日起,中国大陆及港澳地区停止提供Unity 6及后续版本下载与服务,相关功能由国产引擎“团结引擎”承接。国际版2022 LTS及更早版本仍由Unity中国维护…...
司美格鲁肽用SNAC市场报告:2024年全球市场销售额达到了0.14亿美元
引言:了解司美格鲁肽与SNAC的重要性 在当前的医药领域,司美格鲁肽(Semaglutide)作为一种创新性的治疗2型糖尿病和肥胖症的药物,受到了广泛关注。而SNAC(N-(8-(2-羟苯基)…...
自动驾驶第一性原理
所谓的第一性原理: 就是指从最基本的物理规律,数据逻辑及工程约束条件出发,剥离所有的非本质的假设,直接推导出自动驾驶最核心的要素。 自动驾驶核心框架分解: 1、根本目标: 安全高效的将人/物从A地运送…...
《UE5_C++多人TPS完整教程》学习笔记36 ——《P37 拾取组件(Pickup Widget)》
本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P37 拾取组件(Pickup Widget)》 的学习笔记,该系列教学视频为计算机工程师、程序员、游戏开发者、作家(Engineer, Programmer, Game Developer, Author) Steph…...
Uniswap V2/V3/V4 流动性与价格计算详解
Uniswap V2/V3/V4 流动性与价格计算详解 一、核心概念对比 Uniswap V2 流动性模型: 恒定乘积公式 (x * y = k)价格决定: 完全由池子中的代币数量决定 (price = y/x)流动性衡量: 总储备量代表流动性,直接通过 getReserves() 获取流动性分布: 均匀分布在所有价格点交易费用: 固…...
yum安装MySQL数据库
yum安装方式 优点:操作简单易用。不用单独下载,服务器可以联网且yum源没有问题即可(可以选择国内的163/阿里源) 安装步骤: 1.关闭防火墙和selinux: systemctl stop firewalld ##关闭防火墙 systemctl disable firewalld …...
大联盟(特别版)双端互动平台完整套件分享:含多模块源码+本地部署环境
这是一套结构清晰、功能完整的互动平台组件,适合有开发经验的技术人员进行模块参考、结构研究或本地部署实验使用。 该平台覆盖前端展示、后端服务、移动端资源以及完整数据库,采用模块化架构,整体部署流程简单清晰,适合自研团队参…...
【Code】《代码整洁之道》笔记-Chapter15-JUnit内幕
第15章 JUnit内幕 JUnit是最有名的Java框架之一。就像别的框架一样,它概念简单,定义精确,实现优雅。但它的代码是怎样的呢?本章将研判来自JUnit框架的一个代码例子。 15.1 JUnit框架 JUnit有很多位作者,但它始于K…...
【Java八股】
JVM JVM中有哪些引用 在Java中,引用(Reference)是指向对象的一个变量。Java中的引用不仅仅有常规的直接引用,还有不同类型的引用,用于控制垃圾回收(GC)的行为和优化性能。JVM中有四种引用类型…...
深入探究AI编程能力:ChatGPT及其大规模模型的实现原理
📢 友情提示: 本文由银河易创AI(https://ai.eaigx.com)平台gpt-4-turbo模型辅助创作完成,旨在提供灵感参考与技术分享,文中关键数据、代码与结论建议通过官方渠道验证。 随着人工智能的快速发展,…...
高德地图 JS-SDK 实现教程
高德地图 JS-SDK 实现教程:定位、地图选点、地址解析等 适用地点选择、地址显示、表单填写等场景,全面支持移动端、手机浏览器和 PC端环境 一、创建应用&Key 前端(JS-SDK、地图组件) 登陆 高德开放平台创建应用,…...
【信息系统项目管理师】高分论文:论信息系统项目的整合管理(银行数据仓库项目)
更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 正文一、制定项目章程二、制定项目管理计划三、指导和管理项目的实施四、管理项目知识五、监控项目工作六、实施整体变更控制七、结束项目或阶段正文 2023年6月,我以项目经理的身份,参加了 xx银行xx省分行数…...
dev中使用auto的方法
在dev-c中使用新特性是一样的道理,在他启动编译器来编译代码的时候我们让他加上这个参数就行了,设置方法是:在Tools里面找到Compiler Options打开它,然后把那个Add the following commands when calling compiler:选上勾,在里面加…...
C 语言中经典的数据结构
在 C 语言中,经典的数据结构通常包括以下几种,每种都有其特定的应用场景和实现方式: 1. 数组(Array) 定义:连续内存空间存储相同类型的数据。 特点:随机访问快(O(1))&am…...
小白学习java第12天(下):网络编程
上面我们了解TCP就是三次握手!!! 下面我们就详细介绍一下UDP,就是进行发包(TCP协议类似于就是打电话,你必须进行连接才能进行传输,但是UDP类似于发消息,连不连接我都是可以的&#…...
论文精度:双分支图Transformer网络:视频驱动的3D人体网格重建新突破
论文地址:https://arxiv.org/pdf/2412.01179 目录 一、背景与问题定义 1.1 3D人体网格重建的意义 1.2 现有方法的困境 二、核心创新:DGTR网络架构 2.1 整体框架设计 2.2 全局运动感知分支(GMA) 2.3 局部细节优化分支(LDR) 2.3.1 局部信息聚合 2.3.2 调制图卷积…...
华三IRF堆叠技术
IRF(Intelligent Resilient Framework,智能弹性架构)是华三通信(H3C)自主研发的网络设备虚拟化技术,通过将多台物理设备整合为单一逻辑设备,实现统一管理、高可靠性和灵活扩展。以下是其核心要点…...
第一阶段补充知识
目录 书写脚本使用的相关知识? 备份和冗灾的区别?什么叫DD备份,什么叫DD冗灾? 关于Linux系统优化以及Linux的安全加固? 系统优化 硬件系统优化: 内核参数优化: 网络性能优化: 进程管…...
STM32 HAL库 L298N电机驱动模块实现
一、引言 在机器人、自动化设备等众多应用场景中,电机驱动是一个关键的部分。L298N 是一款常用的电机驱动模块,它可以驱动两个直流电机或一个步进电机。STM32F407 是一款高性能的 ARM Cortex-M4 内核微控制器,结合 HAL 库可以方便地实现对 L…...
Redis的Key的过期策略
我们都知道Redis的键值对是可以设置过期时间的,那么就会涉及到一个问题,Redis到底是如何做到响应快的同时有能快速地释放掉过期的键值对的呢?不卖关子了,直接说答案,那就是Redis两个策略:定期删除和惰性删除…...
ubuntu桌面版使用root账号进行登录
这里写自定义目录标题 第一步:给root账户设置密码,并切换至root账户第二步:注释gdm-autologin文件内的相关内容第三步:注释gdm-password文件内的相关内容第四步:重启系统即可使用root账户登录 第一步:给roo…...
贪心算法(18)(java)距离相等的条形码
在一个仓库里,有一排条形码,其中第 i 个条形码为 barcodes[i]。 请你重新排列这些条形码,使其中任意两个相邻的条形码不能相等。 你可以返回任何满足该要求的答案,此题保证存在答案。 示例 1: 输入:barco…...
CentOS服务器能ping通却无法yum install:指定镜像源解决
文章目录 前言一、问题记录二、解决过程1.修改DNS无效2.指定镜像源 总结 前言 今天有一个项目现场要在一个远程centos服务器上部署产品服务,发现能ping通百度,但是无法yum install 安装基础软件包,开始以为DNS服务器的问题,结果配…...
WebSocket与MQTT
在物联网(IoT)领域,WebSocket和MQTT确实都可以实现实时通信,但它们的核心设计目标、适用场景和角色存在显著差异。以下是两者的对比分析: 1. 协议设计初衷 WebSocket 目标:提供浏览器与服务器…...
【论文解读】MSVM-UNet: Multi-Scale Vision Mamba UNet for Medical Image Segmentation
MSVM-UNet: Multi-Scale Vision Mamba UNet for Medical Image Segmentation 论文链接: https://arxiv.org/abs/2408.13735 Code: https://github.com/gndlwch2w/msvm-unet 来源: 2024 IEEE International Conference on Bioinformatics an…...
Vue表单组件el-form校验规则rules,条件判断rules表单验证显示必填或非必填
在使用 Element UI(一个基于 Vue 的前端框架)的表单验证功能时,你可能想要实现一个规则,使得某些字段在特定条件下成为必填项,或者在满足某些条件时不允许为空。这通常通过自定义校验规则来实现。 <template>&l…...
手动关闭ArcGIS与ArcGIS Online连接的方法
【关闭软件启动时ArcGIS与ArcGIS Online连接方法】 打开C盘找到文件夹“C:\Program Files (x86)\Common Files\ArcGIS\bin”,如下图,删除“ArcGISConnection.exe”与“ArcGISConnectionTest.exe”文件,软件下次启动的时候就不会建立与ArcGIS …...
(二十五)安卓开发一个完整的登录页面-支持密码登录和手机验证码登录
下面将详细讲解如何在 Android 中开发一个完整的登录页面,支持密码登录和手机验证码登录。以下是实现过程的详细步骤,从布局设计到逻辑实现,再到用户体验优化,逐步展开。 1. 设计登录页面布局 首先,我们需要设计一个用…...
【过程控制系统】PID算式实现,控制系统分类,工程应用中控制系统应该注意的问题
目录 1-1 试简述过程控制的发展概况及各个阶段的主要特点。 1-2 与其它自动控制相比,过程控制有哪些优点?为什么说过程控制的控制过程多属慢过程? 1-3 什么是过程控制系统,其基本分类是什么? 1-4 何为集散控制系统…...
测试第三课-------自动化测试相关
作者前言 🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂 🎂 作者介绍: 🎂🎂 🎂 🎉🎉🎉…...
关于数据清洗和数据处理实践学习笔记
一些可能想要知道的: pandas是一个模板,它读取的数据都是dataframe的格式,即df Matplotlib是一个用于数据可视化的Python库,能够生成各种静态、动态和交互式图表 pyplot:Matplotlib 的核心接口模块,提供类…...
ubuntu学习day2
linux常用命令 3.文件查看及处理命令 3.1查看文件内容 cat[选项][文件] -b 对非空输出行编号 -E 在每行结束处显示$ -n 对输出的所有行编号 -s 不输出多行空行 标准输入、标准输出和标准错误 在 Linux 中,每个进程默认有三个文件描述符: 标准输入&…...
JavaScript `new Date()` 方法移动端 `兼容 ios`,ios环境new Date()返回NaN
在 iOS 环境下,new Date() 方法会返回 NaN,这通常是由于时间字符串的格式问题。iOS 的 Date 构造函数对时间字符串的格式要求比其他平台更严格。 原因:ios端不兼容“-”为连接符的时间。 解决办法: 替换时间格式 IOS 不支持某…...
考研408参考用书:计算机组成原理(唐朔飞)介绍,附pdf
我用夸克网盘分享了「《计算机组成原理》第2,3版 唐朔飞」, 链接:https://pan.quark.cn/s/6a87d10274a3 1. 书籍定位与适用对象 定位:计算机组成原理是计算机科学与技术、软件工程等专业的核心基础课程,涉及计算机硬件的底层工作原…...
案例-索引对于并发Insert性能优化测试
前言 最近因业务并发量上升,开发反馈对订单表Insert性能降低。应开发要求对涉及Insert的表进行分析并提供优化方案。 一般对Insert 影响基本都在索引,涉及表已按创建日期做了分区表,索引全部为普通索引未做分区索引。 优化建议ÿ…...
@Async 为什么要自定义线程池,使用默认线程池风险
为什么要自定义线程池而非使用默认线程池 使用Spring的Async注解时,如果不自定义线程池而使用默认线程池,可能会带来一些风险和问题。以下是主要原因: 默认线程池的风险 无限制的资源消耗 默认线程池使用SimpleAsyncTaskExecutor࿰…...
Spark-SQL简介与编程
1. Spark-SQL是什么 Spark SQL 是 Spark 用于结构化数据(structured data)处理的 Spark 模块。 Hadoop与Spark的对比 Hadoop的局限性 Hadoop无法处理结构化数据,导致一些项目无法推进。 例如,MySQL中的数据是结构化的,Hadoop无法直接处理。…...
如何分析 JVM OOM 内存溢出 Dump 快照日志
文章目录 1、需求背景2、OOM 触发3、Dump 日志分析 1、需求背景 企业开发过程中,如果系统服务客户量比较大,偶尔会出现OOM内存溢出问题,导致服务发生宕机,停止对外提供访问。 这种情况就需要排查定位内存溢出的原因(…...
系统监控 | 简易多个内网服务器的CPU和内存使用率监控 system_moniter
效果图 原理 一台主机A上运行mysql数据库,接收数据。 其他主机设置定时任务,每6分钟发送一次自己的CPU和内存使用百分数到主机A。 主机A上提供flask为后台的可视化网页,见上图。 源码库 https://github.com/BioMooc/system_moniterhttps:/…...
【神经网络】python实现神经网络(四)——误差反向传播的基础理论
一.反向传播 本章将介绍能够高效计算权重参数的梯度的方法——误差反向传播法,这里简单介绍一下什么是反向传播,加入有个函数y = f(x),那么它的反向传播为图下这个样子: 反向传播的计算顺序是,将输入信号E乘以节点的局部导数,然后将结果传递给下一个节点。这里所…...
Django 开发服务器
$ python manage.py runserver $ python manage.py runserver 666 # 用 666 端口 $ python manage.py runserver 0.0.0.0:8000 # 让局域网内其他客户端也可访问 $ python manage.py runserver --skip-checks # 跳过检查自动检查 $ python manage.py runserver --…...
嵌入式基础(二)ARM基础
嵌入式基础(二)ARM基础 1.精简指令集和复杂指令集的区别⭐⭐⭐ 精简指令集 (RISC) 精简指令集 (Reduced Instruction Set Computing) 具有简洁、精简的指令集,每条指令执行的操作都很基础,使得处理器设计更简单。RISC 处理器通…...
RNA免疫共沉淀测序(RIP-seq)
技术简介 RNA免疫共沉淀测序(RNA Immunoprecipitation Sequencing, RIP-seq)是一种将RNA免疫共沉淀(RIP)与二代测序技术(NGS)相结合,用于研究细胞内RNA与蛋白相互作用的技术。 技术原理 利用目…...
期指跌对股市的影响是什么?
国内股指期货对大盘的影响,这种一般就是不想再买这种指数,大多数都在蓝筹股方面,题材股很少,股指期货是保证金交易,一手大概在15-18W,它的价格是根据指数(如上证指数、深证成指)来确…...
基于Python的LSTM、CNN中文情感分析系统
大家好,我是徐师兄,一个有着7年大厂经验的程序员,也是一名热衷于分享干货的技术爱好者。平时我在 CSDN、掘金、华为云、阿里云和 InfoQ 等平台分享我的心得体会。 🍅文末获取源码联系🍅 2025年最全的计算机软件毕业设计…...
Neovim安装及lazy配置
安装neovim 官网下载 配置lazy插件总成 lazy官网 一般在C盘里会有一个nvim-data,然后用官网里的命令会生成一个nvim 安装C编译器 参考此文 插件都放在目录’C:\Users\wnlea\AppData\Local\nvim\lua\plugins’中,所以新建一个插件,起名为vi…...
什么叫“架构”
我们学硬件架构的时候常常被一些名词和概念绕晕,这篇就来讲一讲“架构”这个概念,一种“架构”指的是什么,如何去学习一种新的架构。 1.架构:硬件设计与指令集的统一体 这里放上我大二下的手写笔记: 就是说硬件设计…...
【Python浅拷贝与深拷贝详解】
目录 前言:技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析核心概念图解关键技术模块技术选型对比 二、实战演示环境配置要求核心代码实现(10个案例)案例1:列表嵌套列表案例2:字典嵌套列表案例3…...