news 2026/9/16 12:05:39

用SkyWalking当靶子,系统掌握接口与性能测试实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用SkyWalking当靶子,系统掌握接口与性能测试实战

想靠刷题学好测试,天花板很低。我接触过不少想转测试或者刚入行的朋友,最容易卡在同一个环节:教程里的接口测试、性能测试都看了,一碰到真实系统就不知道怎么下手。后来我带人练手,发现拿一个开源项目当靶子是最快的路子。这里面我特别推荐 SkyWalking——它不是“又一个要学的工具”,而是一个天然适合被测试的分布式链路追踪系统。围绕它做测试学习,你能把功能测试、接口测试、性能测试、异常测试、自动化回归练一个遍,而且每一步都能看到直接的成果反馈。这篇文章就给你梳理一套完整的 SkyWalking 测试学习思路,从环境搭建到用例设计,再到常见坑位,照着做基本能少走两三个月的弯路。

1. 为什么拿 SkyWalking 当测试学习靶子

1.1 一个项目覆盖了多种测试类型

SkyWalking 本身不是个小玩具,它包含 Java Agent 探针、OAP 分析平台、Web UI、存储后端(默认 ES)这几大块。你用测试视角去看,它其实是一个“带完整前后端和数据通道的系统”,可测的面非常多:

  • 功能层面:UI 上的拓扑图、链路查询、指标看板、告警规则;
  • 接口层面:OAP 的 GraphQL 查询接口、gRPC 上报接口;
  • 性能层面:Agent 对业务应用的额外开销、OAP 在高并发流量下的处理能力;
  • 数据层面:Trace、Segment、Span 是否丢失、结构是否完整、时间戳是否合理;
  • 异常层面:Agent 挂了怎么办、OAP 重启后数据能不能补、存储不可用是什么表现。

对于学习测试的人来说,最大的好处是“问题可观察、结果可验证”。你发一笔请求,过几秒去 UI 上就能查链路,写错了、漏了,肉眼可见。这种反馈速度,是刷一百道面试题都给不了的。

1.2 链路追踪系统的测试难点:数据对不对

链路追踪系统和普通 Web 系统的测试思路有很多不同。普通系统你测的是“接口回没回、状态码对不对”,而 SkyWalking 这类系统,核心难点是数据经过一条很长管道后的完整性:业务服务产生 trace -> Agent 采集 -> gRPC 批量上报 -> OAP 分析聚合 -> 写入 ES -> UI 查询展示。

这里头每一步都可能有数据缺失或变形。gRPC 是批量上报的,OAP 是按窗口做聚合的,ES 写入有延迟,UI 查询有分页限制。所以测试时不能只看界面好不好看,而是要设计“数据对账”的用例:预先知道发送了多少请求、产生了多少 span,查询的时候核对数量有没有少、父子关系对不对。这种“设计校验口径”的能力,恰恰是很多测试新人最缺的,也是找工作时最容易拉开差距的地方。

1.3 通过它你能练到的测试技能

我把通过 SkyWalking 能练到的技能和对应的实践点整理成一个表,方便你对照着做学习规划:

技能方向对应实践点
接口测试调用 OAP 的 GraphQL 接口查 trace、查指标,写断言
自动化测试用 Python / 脚本完成造数、查询、校验、报告
性能测试用 JMeter 压 OAP;对比业务应用加不加 Agent 的 RT 差异
数据测试检查 span 数量、时间戳、traceId 串联、拓扑关系
异常测试kill 掉 OAP、停 ES、模拟 Agent 上报超时
兼容性测试换存储后端、换版本组合,验证系统表现

这套技能树搭下来,不是“会点 JMeter 名词”的程度,是真正能上手干活的程度。

2. 搭一个“最小可测系统”,先跑通一条链路

2.1 被测系统架构拆解:你手上到底有几个部件?

要测试一个系统,第一步一定不是找工具,而是把被测对象的部件摸清楚。SkyWalking 最常见的部署形态里,有四个角色:

  • Java Agent:以-javaagent方式挂到业务应用上,用字节码增强技术拦截 HTTP 请求、数据库访问等动作,生成 trace 数据。
  • OAP Server:负责接收 agent 上报的数据,做分析、聚合、告警判定,对外提供查询接口。
  • SkyWalking UI:一个浏览器端界面,把链路和指标可视化。
  • 存储后端:OAP 将处理后的数据写入 ES(也支持 MySQL、BanyanDB 等),UI 查询时由 OAP 从存储读数据。

端口方面,你最好一开始就记牢:Agent 上报到 OAP 的 gRPC 默认端口是 11800,OAP 对外提供查询的 HTTP 端口是 12800,UI 默认跑在 8080。

数据模型方面,一条用户请求最终形成一棵 trace 树,树上有多个 segment 片段——每个服务进程会生成一段 segment,segment 里包含多个 span。span 又分三种:EntrySpan(服务入口)、ExitSpan(发起外部调用)、LocalSpan(本地逻辑)。这些概念不用死记,但你造数据、写断言的时候一定会用到,比如断言“这次请求产生了两个 segment、三个 span”时,得先知道它们分别代表什么。

2.2 用 Docker Compose 快速搭环境:版本和端口是关键

常规的搭建流程网上有很多文章,但如果你只是为测试学习做准备,我建议直接用 Docker Compose 一把梭,把 OAP、UI、ES、一个 demo 服务串起来。

下面是一个我调过的简版 Compose 配置(版本组合是 SkyWalking 9.x + ES7,已经实测可跑):

version: '3' services: es7: image: docker.elastic.co/elasticsearch/elasticsearch:7.17.9 container_name: sw-es7 environment: - discovery.type=single-node - xpack.security.enabled=false ports: - "9200:9200" oap: image: apache/skywalking-oap-server:9.6.0 container_name: sw-oap depends_on: - es7 environment: - SW_STORAGE=elasticsearch - SW_STORAGE_ES_CLUSTER_NODES=es7:9200 - SW_CORE_GRPC_PORT=11800 - SW_CORE_REST_PORT=12800 ports: - "11800:11800" - "12800:12800" ui: image: apache/skywalking-ui:9.6.0 container_name: sw-ui depends_on: - oap environment: - SW_OAP_ADDRESS=http://oap:12800 ports: - "8080:8080"

提示:网上很多文章会直接docker run单跑 OAP,但那样会漏掉 ES 依赖。本地测试至少要把存储和 OAP 放同一套 Compose 里,否则 OAP 会一直报 index 不存在。

一个最容易踩的坑是版本乱配。SkyWalking 的 Agent、OAP、UI 三者的版本要尽量一致,存储的索引结构也跟版本强相关。我见过有人 UI 用的 8.x、OAP 用的 9.x,最后页面上一直报查询失败,排查半天才发现是版本不匹配。

2.3 制造可控的测试数据:让调用链“可预期”

环境起来之后,不能空着练手,得有自己的“业务”。我的做法是准备两个 Spring Boot 服务:一个 order-service,一个 user-service。order 服务在创建订单时会通过 RestTemplate 调用 user 服务查询用户信息,这样就能产生一条跨服务的真实调用链。

启动时给两个服务各加一段 Agent 参数:

java -javaagent:/path/to/skywalking-agent.jar \ -Dskywalking.agent.service_name=order-service \ -jar order-service.jar

这样访问一次GET /order/create,大约半分钟到一分钟内在 UI 的“拓扑图”页面就能看到 order-service 和 user-service 两个节点的连线,链路查询里能看到一个包含两个 segment 的 trace。

为什么强调“可控”?因为测试用例需要可重复。如果你每次去 UI 上随便点,数据毫无规律,你没法写断言。造数据控制在两种场景里就够了:正常的 200 请求,以及故意让某个接口抛异常的 500 请求。前者用来验证链路完整、耗时正常,后者用来验证错误链路的状态标记和告警触发。

2.4 测试基线:先定义“什么算正常”

很多新手一上来就看图,图有就有,没有就觉得“系统坏了”。这不对。你要在写第一条用例之前,先定义一个可量化的基线,否则后面自动化无从谈起。

我用的基线一般是三个维度:

  • 数量完整:一次请求对应一条 trace;一个跨服务调用会拆成两段 segment;每个 span 都有上游 parentSpanId 串联。
  • 结构正确:EntrySpan 在最外层,ExitSpan 的下游能续接上对端服务的 EntrySpan;service 节点之间有清晰的 client/server 关系。
  • 数据合理:开始时间、结束时间、耗时是正数且单调递增,endpoint 名字与代码路径能对上。

这是你自己定的验收口径。搞明白“什么算正常”,你才能谈“现在到底有没有 bug”。这也正是测试的核心思维:不是把系统点一遍,而是先建立预期,再去做验证。

3. 按测试类型拆解:功能、接口、性能、异常

3.1 功能测试:从 UI 到告警,别漏掉边界

功能测试是最容易上手、也最容易做“假”的一层。很多人打开页面点两下截图就算测完了,这不行。我建议你把 UI 拆成模块写用例:

  • 拓扑图:服务节点和连线是否正确显示;服务名是否和 agent 配置一致;删除一个服务后图会不会淡出。
  • 链路查询:按时间范围、按服务名、按 traceId、按 endpoint 筛选,组合条件是否生效;查询结果分页是否正确。
  • 指标看板:响应时间、吞吐量曲线是否在请求后出现变化;刷新频率和数据窗口是否符合预期。
  • 告警列表:配置一个“最近 3 分钟成功率低于 80%”的规则,然后用脚本打一批 500 请求,看告警能不能触发、恢复后会不会自动清除。

边界情况是最容易漏的:默认时间范围通常是“最近 15 分钟”,但如果被测服务刚好在 16 分钟前产生过数据,页面就会一片空白,新手很容易误判成系统故障。再比如跨天查询,很多 UI 组件对跨日期的查询条件处理不好,这也是值得记录的一条功能 bug。

注意:SkyWalking 的 UI 查询结果不是实时的。链路数据从 Agent 采集到 OAP 聚合再到 ES 索引可见,会有 30 秒到几分钟的延迟。功能用例里要设计显式等待,否则会出现“请求发送成功但 UI 查不到”的假失败。

3.2 接口测试:直接查 OAP 的 GraphQL 接口

UI 上看到的所有图表,底层都是 OAP 的 GraphQL 接口。既然要学接口测试,那就不该停留在 Postman 打一个 GET 请求的水平,而是应该学会向 GraphQL 端点发送结构化查询,并做字段级断言。

OAP 的 12800 端口暴露了/graphql端点,你可以用 Python 直接请求:

import requests OAP_ENDPOINT = "http://127.0.0.1:12800/graphql" query = """ query queryTraces($condition: TraceQueryCondition) { queryTraces(condition: $condition) { traces { key: segmentId endpointNames duration start isError } } } """ variables = { "condition": { "queryDuration": { "start": "2025-01-01 000000", "end": "2025-01-01 235959", "step": "MINUTE" }, "traceState": "ALL", "queryOrder": "BY_START_TIME", "paging": {"pageNum": 1, "pageSize": 10} } } resp = requests.post(OAP_ENDPOINT, json={"query": query, "variables": variables}) assert resp.status_code == 200 data = resp.json() assert "errors" not in data print(data["data"]["queryTraces"]["traces"])

提示:不同版本的 GraphQL Schema 字段可能有差异,写脚本前先在 OAP 的/graphql上用自带的文档面板确认字段名。我用的是 9.x 的结构,8.x 大体兼容,但个别字段会有变动。

接口测试的重点不是“调通”,而是“断言”。我常用的断言组合:

  • 状态断言:HTTP 200,且data节点里没有errors
  • 数量断言:返回的 trace 条数不小于预期;分页大小为 10 时,最多返回 10 条。
  • 结构断言:trace 里包含两个以上 segment,且 segment 之间有父子级联关系。
  • 业务断言:isError 字段与造数时的 500/200 结果一致。

3.3 性能测试:既要压 OAP,也要测 Agent 的损耗

一说到性能测试,新手第一反应就是“上 JMeter,给系统上压”。但链路追踪系统的性能测试,至少要拆成两个方向:一个方向是压 OAP 本身的查询能力和写入能力;另一个方向是测 Agent 挂在业务应用上带来的额外开销。

先看 OAP 这边。你可以用 JMeter 建一个线程组,专门打 OAP 的/graphql查询接口。我常用的压测参数是:线程数 100,Ramp-up 周期 10 秒,循环次数 20,总共 2000 个请求。请求体就是 3.2 节那个 GraphQL 查询,聚合报告里主要看三项:平均响应时间、错误率、吞吐量。这个时候你关注的是 OAP 的 CPU、堆内存,以及 ES 的写入队列,而不是业务应用本身。

再看 Agent 损耗。这个测试设计更有意思:同样的业务接口,在不开 Agent 的情况下压测,记录 TPS 和 RT;然后在同样条件下开启 Agent,再压测一轮,对比两个结果。两份数据之间的差,就是 SkyWalking 对业务应用的额外开销。

场景平均 RTTPS观察项
未接 Agent2.1 ms1860基线
接入 Agent2.6 ms1520额外开销约 20% 左右

这套对比数据,在面试或项目汇报里非常好用,因为它体现了“测试不是只会点按钮,而是能设计实验来量化影响”。如果你发现 Agent 带来的开销异常放大,优先检查采样率配置和 Agent 版本。

注意:性能测试环境要和功能测试环境分开,或者保证数据量基线一致。否则 ES 里积累了几十万条历史数据,查询性能的压测结果会严重失真。

3.4 异常场景与故障注入:这组用例最能拉开差距

普通功能用例大家都会写,真正体现测试水平的是异常场景。做这类测试前一定要准备隔离环境,别在给客户演示的机器上随便 kill 进程。下面是我实际跑过的故障注入清单:

  • 停止 ES 容器:OAP 仍然能启动,但所有查询接口会报存储错误;此时 Agent 照常上报,OAP 堆积数据。重启 ES 后,堆积的 trace 会被继续写入,但期间的数据查询会全部失败。
  • 直接 kill OAP 进程:Agent 会不断重连,gRPC 客户端会在后台持续尝试恢复。把 OAP 重新拉起后,Agent 会在几秒内重连成功,中间积压的数据会补传上来。我测试时观察到补传窗口大约在 5 到 30 秒之间。
  • 模拟 Agent 上报延迟:通过防火墙规则或 tc 命令给 11800 端口加延迟,观察 Agent 的内存占用是否增长、业务接口 RT 是否因此受影响。
  • 手动改动系统时间:这个操作比较“脏”,但能验证时间戳问题。把测试机器的时间往前调 1 小时,再发请求,UI 链路查询里会出现排序错乱,这也是一个典型的数据正确性 bug。

异常用例的关键是记录“预期行为”。比如 “OAP 重启后不再接受 Agent 上报,但 Agent 不崩溃、业务不受影响”,这就是一条合格的需求描述。把这些用例沉淀成文档,比单纯写“XXX 挂了”有价值得多。

4. 自动化回归:造数据、写断言、接流水线

4.1 自动造链路数据:模拟多服务调用和异常 trace

做自动化回归的第一步,是解决“数据从哪来”的问题。手工点接口造数撑不了几次,我建议用一段简单的脚本定时向 demo 服务发请求,同时随机混入一部分错误请求和慢请求,让被测系统里的链路数据保持“有正常、有异常、有慢调用”的状态。

import random import time import requests demo_urls = [ "http://127.0.0.1:8082/order/create", "http://127.0.0.1:8082/order/get", "http://127.0.0.1:8082/user/info" ] for i in range(200): url = random.choice(demo_urls) try: if random.random() < 0.1: # 10% 概率制造错误请求 requests.post(url + "?error=1", timeout=3) elif random.random() < 0.2: # 20% 概率制造慢请求 requests.post(url + "?sleep=2000", timeout=5) else: requests.get(url, timeout=3) except Exception as e: print(f"request error: {e}") time.sleep(0.2)

这段脚本每次跑完,SkyWalking 里就会有一批分布相对固定的 trace 数据,足够支撑自动化用例的断言。造数这件事,占整个自动化工作量的三成左右,但它决定了后面所有用例是否稳定,值得认真对待。

4.2 一套 Python 接口自动化用例示例

接口自动化我推荐用 pytest,配合 requests 就够了。用例的逻辑很简单:先确认环境里有一定数量的 trace,再按条件查询并校验关键字段。

下面是一段能直接跑的用例骨架:

import requests import pytest BASE = "http://127.0.0.1:12800/graphql" def query_traces(page_size=5): payload = { "query": """ query ($condition: TraceQueryCondition) { queryTraces(condition: $condition) { traces { key endpointNames duration start isError } } } """, "variables": { "condition": { "queryDuration": { "start": "2025-01-01 000000", "end": "2025-01-01 235959", "step": "MINUTE" }, "traceState": "ALL", "queryOrder": "BY_START_TIME", "paging": {"pageNum": 1, "pageSize": page_size} } } } resp = requests.post(BASE, json=payload, timeout=5) assert resp.status_code == 200 return resp.json() def test_query_traces_success(): data = query_traces() assert "errors" not in data traces = data["data"]["queryTraces"]["traces"] assert len(traces) > 0 def test_trace_has_expected_fields(): data = query_traces(page_size=1) trace = data["data"]["queryTraces"]["traces"][0] assert "key" in trace assert trace["duration"] >= 0 assert isinstance(trace["isError"], bool)

运行方式:pytest test_skywalking.py -v。这套用例虽然简单,但它能保证 OAP 查询接口没有根本性故障,适合作为每次版本升级后的冒烟测试。

我建议把“硬件检查”也混在自动化里:定时调用curl http://127.0.0.1:12800/graphql探活,如果返回非 200,就自动发一封告警邮件。这样做的好处是,你不需要每天手动打开界面确认系统还活着。

实战经验:断言超时时间不要设得太短。OAP 在首次冷启动或 ES 索引重建期间,GraphQL 查询可能长达 5 秒才能返回。如果断言超时设成 2 秒,会频繁出现假失败,干扰真正的问题排查。我一般设 5 到 8 秒。

4.3 断言与基线管理:不要用“肉眼看图”代替校验

自动化测试最忌讳的一条,是跑完脚本后打开 UI 截图“看结果”。这样根本没有起到回归的作用,因为人眼很难发现数据量的细微偏差。我的做法是把每次执行后的关键指标存成 JSON,作为“基线”,下次跑完再和基线做 diff。

比如基线文件baseline.json长这样:

{ "query_time": "2025-01-01 00:00:00", "total_traces": 128, "error_traces": 12, "avg_duration_ms": 186, "max_duration_ms": 2300, "service_count": 2 }

测试脚本结束前,自动读取当前查询结果和基线对比,超过阈值就失败。阈值怎么定?我的经验是:正常造数脚本跑一轮,total_traces 上下浮动不超过 10%,error_traces 比例不超过 15%。如果超过这个范围,大概率是造数脚本或被测系统出了问题,需要人工介入。

有了基线管理,你才能在做了代码改动、版本升级、配置调整之后,快速发现“这次改动是不是影响了链路数据的完整性”。这也是自动化回归真正的价值——不是跑给领导看,而是真的能拦住回归问题。

4.4 用 JMeter 做并发测试的几个细节

JMeter 是压测 OAP 查询接口的常用工具,但它有几个细节特别容易踩坑,我单独拎出来说:

第一,GraphQL 请求体要用 HTTP 请求采样器发送,不要用普通的 GET 参数拼接。完整的 JSON 体放在“Body Data”选项卡里,Content-Type 设置为application/json。如果用 CSV 参数化 traceId,注意编码格式要选 UTF-8,否则中文 endpoint 名可能乱码。

第二,线程组参数不要盲目学习网上的“1000 并发”。本地测试虚拟机上,OAP 的处理能力有限,我建议初始参数是线程数 50,Ramp-up 5 秒,循环 10 次,先看基线,再逐步上调。你压本地环境的目的不是测出极限值,而是学会“如何判断系统接近瓶颈”。

第三,JSR223 断言中可以直接解析响应里的errors字段,判断查询是否成功。光有 HTTP 200 不够,GraphQL 的业务错误也在 200 里返回。

def json = new groovy.json.JsonSlurper().parseText(prev.getResponseDataAsString()); if (json.errors != null) { prev.setSuccessful(false); prev.setResponseMessage("GraphQL errors: " + json.errors); }

这个断言逻辑,比默认的“响应代码=200”要严格得多,能帮你抓住数据层面的异常。

5. 技能树横向扩展:从链路追踪到测试全栈

5.1 深入探针:字节码增强与异步场景测试

测试学到一定程度,你会想往更深处走。SkyWalking 的 Java Agent 用的是字节码增强,也就是在类加载时修改方法的执行逻辑,把埋点代码织入进去。这种机制带来的测试挑战是:不是所有代码路径都会被自动埋点,特别是异步线程、消息队列消费、定时任务场景。

我建议你有空去读一下 Agent 插件的测试目录,里面全是真实场景的测试用例。比如apm-spring-cloud-gateway-plugin插件,怎么验证一个请求经过网关转发后,trace 上下文还能保持不丢。你不需要读懂每一行源码,但至少要理解:

  • 插件生效的前提是什么(依赖包存在,且类被加载到特定的 ClassLoader)
  • 异步线程为什么容易丢链路(ThreadLocal 在线程池场景下并不会自动传递)
  • 这类问题怎么在测试中复现(用线程池发异步请求,观察 UI 链路是否被切断)

这些知识点在普通功能测试里永远不会碰到,但它们才是链路追踪系统真正有深度的测试场景。学会这几个场景,你的测试面试深度会明显上了一个台阶。

5.2 交叉练习:用类似工具或漏洞平台补盲区

没有一种技术是孤立的。SkyWalking 练熟之后,我强烈建议你做两件横向扩展的事。

第一件事是拿同类工具做对比测试。Zipkin、Jaeger、SkyWalking 都是链路追踪方案,但数据模型、采样策略、存储设计完全不同。你可以设计同一份业务负载,分别接入三种方案,对比它们的埋点完整性、查询响应时间、资源占用差异。这种“横向评测”本身就是一种标准的测试工作,做出来就是一份很有分量的技术文档。

第二件事是补一下安全测试的基础。想在测试这条路上走得更远,安全测试的能力很加分。你可以本地搭一个开源的漏洞靶场,比如 pikachu,通过它理解 SQL 注入、XSS、越权等常见漏洞的成因和测试思路,再回头审视 SkyWalking 的一些接口是否存在类似的参数校验缺陷。整个过程要在自己搭的本地环境里做,合法合规。

5.3 一个可执行的三个月学习路线

最后给一套我的个人节奏,你可以按自己的情况微调:

  • 第 1 周:搭好完整环境,把一条跨服务的链路跑通。只要能亲自在 UI 上看到 order-service 调 user-service 的 trace,就算过关。
  • 第 2 周:不做 UI 操作,所有查询都用 GraphQL 接口来完成。强制自己用脚本代替手工点页面。
  • 第 3 周:写第一版自动化用例,覆盖 trace 查询和字段断言。先跑通 10 条用例,再追求数量。
  • 第 4 周:开始做性能测试,记录 OAP 查询接口的基线和 Agent 的开销数据。
  • 第 5 周:做故障注入测试,把 OAP、ES、Agent 三个角色各搞挂一次,记录恢复行为和影响范围。
  • 第 6 周起:把所有用例和基线管理接入本地 CI,比如每天定时跑一遍,输出一份报告。

这个路线没有堆砌概念,每一步都是可操作的任务。你如果真的完整走下来,对你测试能力的提升会比上两个月网课更明显。

我自己的感觉是,测试学习最有用的东西不是某个工具,而是建立“系统思维”。SkyWalking 恰好是一面很好的镜子,它把请求的来龙去脉拆得清清楚楚,理解它之后,你再看其它分布式系统,会自然带着“这条数据从哪来、到哪里去、丢了怎么发现”的视角去看,这才是真的收获。

关于时间的校验,我一直建议测试机装 NTP 同步。链路追踪最怕的就是机器时钟偏了,一旦偏了,trace 时间线乱成一团,排查起来极容易误判。所以,最后再分享一个小技巧:每次搭测试环境时,先跑一下date确认时间正常,这能省下你后面大量的排查时间。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 12:04:38

三方API代付系统开发实战:余额充值接口与易支付对接全解析

简介&#xff1a;这套第三方API代付系统源码主要面向需要快速接入微信、支付宝、QQ三大主流代付通道的个人开发者与企业运营者&#xff0c;解决API接口易失效、资金划拨成本高、汇款管理繁琐等问题。系统后台地址为/admin&#xff0c;默认账号admin&#xff0c;密码123456&…

作者头像 李华
网站建设 2026/9/16 12:03:58

广度优先搜索(BFS)算法详解与力扣实战

1. 广度优先搜索算法解析广度优先搜索&#xff08;Breadth-First Search&#xff0c;简称BFS&#xff09;是一种用于遍历或搜索树或图的算法。它从根节点开始&#xff0c;先访问所有相邻节点&#xff0c;再依次访问这些相邻节点的相邻节点&#xff0c;以此类推&#xff0c;直到…

作者头像 李华
网站建设 2026/9/16 12:03:04

VS2019开发安卓APP真相:Xamarin跨平台实战指南

1. 项目概述&#xff1a;VS2019真能直接写安卓APP&#xff1f;先说清楚这件事的边界很多人看到“用VS2019开发安卓APP”这个标题&#xff0c;第一反应是——微软的Visual Studio 2019不是写C#、做Windows桌面或Web应用的吗&#xff1f;怎么还能编安卓&#xff1f;这背后其实藏着…

作者头像 李华
网站建设 2026/9/16 12:02:47

欧姆龙PLC以太网FINS协议C++通讯实例与源码解析

简介&#xff1a;欧姆龙PLC以太网C/C通讯实例源码是一套面向工业自动化上位机开发的程序源代码包&#xff0c;重点解决VC环境下与欧姆龙PLC的以太网通讯难题。源码将握手连接、数据读写等逻辑封装为独立类&#xff0c;调用方实例化后按接口传入参数即可使用&#xff0c;极大降低…

作者头像 李华
网站建设 2026/9/16 12:01:50

uniTerm v1.9实测:14MB开源终端如何完美替代MobaXterm

说实话&#xff0c;这两年我电脑里的终端工具换了好几轮&#xff0c;但每次折腾完又忍不住装回 MobaXterm。没办法&#xff0c;它确实太全面了&#xff1a;SSH、SFTP、串口、FTP、远程桌面全都能干&#xff0c;绿色版拷进 U 盘就能带着跑。可它的问题也随着年龄增长越来越明显—…

作者头像 李华