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

lsquic实战《一》—— 架构解析与核心概念入门

1. 初识lsquic它是什么以及为什么选择它如果你正在寻找一个用C语言实现的、功能齐全且文档相对友好的QUIC协议库来开发你的网络应用那么lsquic很可能已经进入了你的视野。我当初选择它也是基于类似的考量项目需要引入QUIC协议来优化传输性能在对比了几个开源实现后lsquic以其清晰的架构、对最新协议版本如QUIC v1和多个草案版本的支持以及相对活跃的社区成为了我的首选。简单来说lsquic就是一个工具包它帮你处理了QUIC协议里所有复杂、繁琐的底层细节比如加密握手、连接管理、流的多路复用、丢包重传等等让你能更专注于自己的业务逻辑。但lsquic有一个非常鲜明且重要的特点这也是它和很多“大而全”的网络库最不一样的地方它本身不提供网络I/O和事件循环机制。这句话什么意思呢回想一下我们用过的Libevent、Libuv或者甚至是简单的select/poll这些库的核心工作之一就是帮你管理socket告诉你什么时候可以读数据、什么时候可以写数据。lsquic把这块工作完全交给了使用者。它不会自己去创建socket也不会内置一个事件循环来驱动整个程序。听起来是不是有点“麻烦”但恰恰是这种设计赋予了它极大的灵活性。你可以把它轻松地“嵌入”或“嫁接”到你现有的任何网络框架中无论你这个框架是基于epoll、kqueue的还是基于某个异步IO库的。你只需要告诉lsquic“当有数据需要发送时请调用我这个函数当有外部事件比如定时器到期需要处理时也请调用我这个函数。” 剩下的协议逻辑就全交给lsquic了。这种“回调驱动”的架构模式对于已经有一套成熟网络处理模型的开发者来说其实非常友好。你不需要为了迁就lsquic而重写整个网络层只需要实现几个约定的回调接口就能把QUIC这颗强大的“引擎”装进你自己的“汽车底盘”里。在接下来的内容里我会带你一步步拆解lsquic的核心部件看看这个引擎到底由哪些零件构成以及我们该如何动手把它组装和运行起来。2. 核心架构拆解Engine, Connection, Stream的三层世界要驾驭lsquic首先得理解它的核心架构模型。你可以把它想象成一个三层结构最底层是负责全局调度和管理的Engine引擎中间层是代表一次端到端会话的Connection连接最上层是承载实际应用数据的Stream流。这个分层非常清晰每一层各司其职共同协作。2.1 Engine全局的大管家Engine是lsquic世界的总指挥部。你的程序启动后第一件要做的事就是创建一个Engine实例。这个Engine负责管理所有从这个程序发起的或者接收到的QUIC连接Connection。它内部会处理很多全局性的事务比如协议版本的协商、全局配置参数的生效、以及最重要的——调度。Engine的调度工作很有意思。因为它自己不跑事件循环所以它需要你告诉它两件事第一什么时候该处理内部事务比如检查超时、触发重传第二如何把要发送的数据包送出去。这是通过两个关键的回调函数实现的一个是处理外部事件的回调比如你告诉Engine“现在有100毫秒的空闲时间你可以做内部处理了”另一个是发送数据包的回调Engine准备好数据包后调用你提供的函数由你负责用socket发送出去。Engine可以初始化为客户端模式或服务器模式。如果你的应用角色比较特殊既需要连接别人也需要被别人连接那么通常的做法是创建两个Engine实例一个客户端一个服务端分别管理不同方向的连接。2.2 Connection可靠的会话通道在Engine的管理之下每一个独立的QUIC会话就是一个Connection。它对应着网络世界中两个端点之间的一条虚拟通道。这条通道是可靠的保证了数据包按序、无误地送达并且所有QUIC协议层面的细节比如加密解密、拥塞控制、连接迁移等都在这一层被处理掉了。从开发者的视角看客户端的Connection是我们主动调用lsquic_engine_connect()函数创建的意图是去连接一个服务器。而服务端的Connection则是在完成TLS握手后由lsquic在内部自动创建然后通过回调函数通知给我们的业务代码。一个Connection可以同时承载多个Stream这正是QUIC多路复用的精髓所在避免了HTTP/2中“队头阻塞”的问题。2.3 Stream应用数据的载体Stream才是我们最终传输业务数据的地方。每一个HTTP/3的请求和响应或者你自定义的应用协议消息通常都会在一个独立的Stream里传输。Stream是双向的意味着两端都可以在上面发送和接收数据。它必须依附于一个Connection不能单独存在。当我们想发送一段数据时操作的是Stream的接口。我们把数据交给某个StreamStream会把它切分成合适大小的帧然后交给它所属的Connection。Connection再将这些帧连同其他Stream的帧以及协议控制帧一起组装成QUIC数据包最后递交给Engine由Engine通过我们设置的回调函数发送出去。接收数据则是相反的过程。这种设计使得应用层逻辑Stream和传输层逻辑Connection得到了很好的分离。3. 关键特性解读不只是“更快”的协议lsquic实现了一系列QUIC协议的关键特性这些特性不仅仅是让协议“更快”更是为了解决传统TCP/TLS协议栈中一些固有的痛点。理解它们能帮助我们在实际项目中更好地利用QUIC的优势。DPLPMTUDDatagram Packetization Layer Path MTU Discovery翻译过来是“数据包化层路径MTU发现”。这听起来很拗口但解决的问题很实际我一次性能发多大的UDP包才能既不被中间的路由器分片分片会降低性能和增加丢包风险又能最大限度地利用网络带宽在TCP里MTU发现是协议栈底层自动做的。但在QUIC里因为整个数据包包括头部和载荷都是被加密的底层网络设备看不到端口信息传统的MTU发现机制可能失效。DPLPMTUD就是QUIC自己实现的一套智能探测机制。它会尝试发送不同大小的探测包根据是否收到对方的确认来动态地找到当前路径上最优的包大小。这个特性默认是开启的对于提升在高MTU网络比如数据中心内部下的传输效率非常有用。Path Migration路径迁移想象一下你的手机从WiFi切换到4G网络IP地址瞬间变了。如果是TCP连接这次连接基本上就断了得重连。但QUIC的连接是使用连接IDConnection ID来标识的而不是传统的四元组源IP、源端口、目的IP、目的端口。当客户端的网络地址发生变化时它可以沿用之前的连接ID通过新的IP地址继续发送数据告诉服务器“我还是我只是换了个地址。” 服务器验证后连接就能无缝地迁移到新的路径上。这对于移动端应用的用户体验是质的提升视频会议、在线游戏等场景受益巨大。lsquic完整地支持了这一特性。NAT Rebinding这和路径迁移解决的是类似但不同的问题。有时候客户端的IP没变但是NAT设备比如你家路由器背后的映射端口超时重建了导致服务器看到客户端的源端口变了。在TCP看来这也是一个陌生的新连接。但QUIC同样能通过连接ID来保持连接的连续性。lsquic在处理这类网络环境变化时表现得相当稳健。其他重要特性ECN显式拥塞通知允许网络设备在数据包上标记拥塞信号让端点更早地调整发送速率避免更严重的丢包。Spin Bit是一个轻量级的机制允许路径上的网络监控设备估算连接的往返时间RTT便于网络诊断。TLS Key Update允许在连接不断开的情况下更新加密密钥增强前向安全性。Datagrams提供了不可靠、无序的数据报传输能力适合音视频流、游戏状态同步等场景。ACK确认延迟则通过适当延迟发送确认包有机会将多个ACK合并发送减少协议开销提升吞吐。4. 实战第一步初始化流程与核心配置了解了架构和特性我们来看看如何把lsquic用起来。整个初始化过程可以概括为配置Engine - 实现回调 - 创建Engine - 将Engine融入你的事件循环。下面我们以客户端为例拆解每一步。4.1 配置的基石lsquic_engine_api和lsquic_stream_if在创建Engine之前我们需要填充两个至关重要的结构体lsquic_engine_api和lsquic_stream_if。它们是你和lsquic引擎之间的“契约”。lsquic_engine_api是给Engine的配置单。里面包含了Engine运行所需的所有信息必须实现的回调ea_packets_out和ea_packets_out_ctx这是最核心的回调。当lsquic有数据包需要发送到网络时就会调用这个函数。你的实现里应该把传入的数据包可能是一个数组通过你的socket发送出去。ea_stream_if指向你实现的lsquic_stream_if结构体的指针告诉Engine你的Stream回调函数在哪里。ea_get_ssl_ctx服务端或ea_ssl_ctx客户端用于提供TLS上下文SSL_CTXlsquic内部使用BoringSSL或类似的库进行加密握手。你需要自己初始化和配置这个SSL_CTX。重要参数ea_version指定你的应用希望使用的QUIC版本号比如LSQVER_I001代表QUIC v1。ea_conn_ctx一个用户自定义的上下文指针它会传递给后续创建的Connection。ea_settings指向一个lsquic_engine_settings结构体里面包含了海量的调优参数比如各种超时时间、流量控制窗口、拥塞控制算法选择等。刚开始可以用默认值后续优化时会经常和它打交道。lsquic_stream_if定义了Stream和Connection生命周期中各个事件发生时lsquic要调用的你的业务函数。其中几个关键的回调是on_new_conn/on_conn_closed当一个新的Connection被创建或关闭时触发。on_new_stream/on_stream_close当一个新的Stream被创建或关闭时触发。对于HTTP/3服务器收到一个客户端发来的新请求时就会触发on_new_stream。on_read当Stream上有可读的数据时触发。你在这个函数里调用lsquic_stream_read()来读取数据。on_write当Stream的写缓冲区有空闲可以继续写入数据时触发。你在这个函数里调用lsquic_stream_write()来发送数据。4.2 创建Engine并融入事件循环配置好lsquic_engine_api后调用lsquic_engine_new()函数就能创建出Engine实例。但这只是开始这个Engine现在还是静止的。要让这个引擎转起来你需要做两件事喂数据给它在你的主事件循环中当你从socket收到UDP数据包时你需要调用lsquic_engine_packet_in()函数把这个原始的数据包交给Engine去处理。Engine会负责解密、解析并触发相应的回调比如on_read。给它处理时间Engine内部有很多后台任务比如检查定时器、处理重传队列。你需要定期地比如每隔10毫秒或在你的事件循环空闲时调用lsquic_engine_process_conns()函数。这个函数给Engine一个“时间片”让它处理这些内部事务。同时在调用这个函数之前或之后你还需要调用lsquic_engine_send_unsent_packets()来触发发送那些待发送的数据包。这个过程清晰地体现了lsquic的“嵌入”式设计你的网络事件循环是主人lsquic Engine是一个高效的工人。你负责把原材料网络包递给工人并定期给他工作时间他负责把原材料加工成产品协议解析并把需要运走的产品输出包交还给你。整个流程的控制权始终在你手里。5. 数据流详解从Socket到应用层的旅程让我们追踪一个数据包在lsquic处理下的完整生命周期这能帮你把前面所有的概念串联起来。5.1 接收数据的旅程假设我们是一个服务器从UDP socket收到一个来自客户端的数据包。Socket层你的事件循环比如epoll告诉你某个socket可读了。你调用recvfrom读到一个UDP数据报datagram。注入引擎你立即调用lsquic_engine_packet_in()将这个数据报的缓冲区、长度、来源地址等信息传入lsquic Engine。Engine处理Engine首先会检查这个包属于哪个已有的Connection通过连接ID。如果是新连接的第一个包Initial包它会开始握手流程。然后Engine会对数据包进行解密和协议解析。触发回调解析后如果这个包里包含某个Stream的应用数据Engine就会调用你在lsquic_stream_if中设置的on_read回调函数。应用读取在你的on_read回调函数实现里你调用lsquic_stream_read()。这个函数会从该Stream的接收缓冲区中把解密后的、有序的、完整的应用层数据拷贝到你提供的缓冲区里。至此你的业务代码才真正拿到了可用的数据。关键点你从socket读到的始终是加密的、原始的QUIC数据包。只有经过lsquic_stream_read()出来的才是你的纯业务数据。这个解密和组序的过程对你是透明的。5.2 发送数据的旅程现在你的业务逻辑想要通过某个Stream发送一段数据。应用写入你调用lsquic_stream_write()将你的数据缓冲区、长度等信息传入。这个函数是非阻塞的它会尽可能多地将数据放入该Stream的发送缓冲区。流与连接处理Stream会按照QUIC帧的格式封装你的数据。然后这些帧被递交给它所属的Connection。连接组装与调度Connection会收集来自各个Stream的帧加上ACK帧、流量控制帧等协议帧按照当前拥塞窗口大小组装成一个或多个QUIC数据包并对其进行加密。然后将这些待发送的包放入Engine的发送队列。引擎通知此时数据并没有被立即发送。Engine会在下次你调用lsquic_engine_send_unsent_packets()时或者在你调用lsquic_engine_process_conns()导致有数据需要立即发送比如ACK时通过你之前设置的ea_packets_out回调函数来通知你。网络写出在你的ea_packets_out回调函数实现里你会收到一个或多个lsquic_out_spec结构体每个里面包含了要发送的数据包缓冲区、目标地址等信息。你的责任就是遍历这个数组调用sendto或类似的socket函数将它们发送到网络上。关键点发送的触发是异步的。你调用写函数只是把数据交给了lsquic真正的网络发送动作发生在lsquic调用你的回调时。你需要确保你的回调函数能高效地将数据包送出避免阻塞。6. 避坑指南与实战心得最后分享几个我在实际使用lsquic过程中踩过的坑和总结的经验希望能帮你少走弯路。第一个坑定时器与事件循环的集成。lsquic内部有很多定时器超时重传、PING保活、空闲超时等。它通过ea_get_event如果实现或通过lsquic_engine_process_conns()的返回值来告诉你下一个内部事件最早在多少毫秒后发生。你必须重视这个返回值一种常见的做法是在你的主事件循环中使用一个高精度的定时器如timerfd将这个返回值设置为定时器的超时时间。这样既能保证lsquic的内部任务得到及时处理又避免了不必要的空转忙等待节省CPU。第二个坑发送回调的性能。ea_packets_out回调可能会被高频调用尤其是在高速传输时。这里的实现一定要高效。避免在回调中进行复杂的逻辑或内存分配。通常的做法是直接遍历数据包数组调用sendmmsg如果系统支持进行批量发送这比循环调用sendto性能好得多。同时要做好EAGAIN/EWOULDBLOCK错误的处理如果socket发送缓冲区满需要将未发送的数据包妥善管理起来等待下次可写事件。第三个坑内存管理。lsquic的很多API如读数据需要你提供缓冲区。你需要清楚这些缓冲区的生命周期。例如lsquic_stream_read()读出的数据其内存是由lsquic内部管理的你不应该释放它。而通过lsquic_stream_write()写入的数据在你提供的回调函数返回之前缓冲区必须保持有效。仔细阅读文档理解每一处内存所有权ownership的归属。第四个心得从默认配置开始逐步调优。lsquic_engine_settings里的参数多达几十个一开始很容易让人头晕。我的建议是除非你有明确的需求否则先从默认配置开始。让你的应用跑起来建立起基本的连接和数据传输。然后通过日志和监控观察是否有性能瓶颈如吞吐上不去、延迟高。再针对性地去调整参数比如增大流量控制窗口、调整PING间隔、尝试不同的拥塞控制算法等。lsquic的日志系统很强大编译时开启调试日志能在开发阶段帮你快速定位问题。第五个心得好好设计你的上下文Context。ea_conn_ctx和lsquic_stream_ctx是你把自己的业务状态和lsquic对象关联起来的桥梁。比如你可以把一个代表用户会话的结构体指针作为Connection的上下文再把其中某个具体请求的处理状态作为Stream的上下文。这样在回调函数里你就能快速定位到对应的业务数据而不需要自己去维护复杂的映射表。刚开始接触lsquic时可能会觉得它比直接使用TCP socket编程要复杂不少。但一旦你理解了它的回调驱动模型并成功地将它集成到你的事件循环中你就会发现它带来的收益是巨大的更低的连接延迟、更好的多路复用能力、以及对移动网络环境的天然友好。更重要的是你对自己的网络栈有了更深层次的控制力。希望这篇架构解析和概念入门能为你开启lsquic实战之旅打下一个扎实的基础。接下来的系列文章我们会深入代码一步步搭建一个可运行的客户端和服务端示例。

相关文章:

lsquic实战《一》—— 架构解析与核心概念入门

1. 初识lsquic:它是什么,以及为什么选择它 如果你正在寻找一个用C语言实现的、功能齐全且文档相对友好的QUIC协议库来开发你的网络应用,那么lsquic很可能已经进入了你的视野。我当初选择它,也是基于类似的考量:项目需要…...

AirSim实战指南:从零构建Python无人机控制脚本

1. 环境准备:搭建你的第一个AirSim仿真世界 想用Python控制无人机在天上自由翱翔,听起来很酷对吧?但别急着写代码,咱们得先把“舞台”搭好。这个舞台就是AirSim,一个由微软开源的、基于游戏引擎(通常是Unre…...

从零到一:在Ubuntu上配置SSH服务并用MobaXterm实现安全远程访问

1. 为什么你需要远程访问Ubuntu?从场景聊起 想象一下这个场景:你刚拿到一台性能不错的服务器,或者在自己的电脑上装好了Ubuntu系统,准备大干一场。但机器放在书房角落,或者干脆是托管在机房的云服务器,你总…...

真实世界研究R代码总被药监局退回?这8个ADaM变量命名雷区,92%的临床数据科学家已中招

第一章:真实世界研究中ADaM合规性困境的根源剖析 在真实世界研究(RWS)中,ADaM(Analysis Data Model)规范的落地常遭遇结构性冲突——其设计初衷面向传统随机对照试验(RCT)的预设数据…...

MiniCPM-o-4.5-nvidia-FlagOS生成LaTeX文档效果:从草稿到排版一气呵成

MiniCPM-o-4.5-nvidia-FlagOS生成LaTeX文档效果:从草稿到排版一气呵成 每次写论文或者技术报告,最头疼的是什么?对我来说,不是想内容,而是排版。那些复杂的数学公式、交叉引用、参考文献格式,还有怎么也调…...

Qwen Pixel Art效果展示:支持1:1/4:3/16:9多种宽高比的像素图精准生成

Qwen Pixel Art效果展示:支持1:1/4:3/16:9多种宽高比的像素图精准生成 还记得小时候玩红白机时,那些由一个个小方块组成的游戏世界吗?那种独特的、充满复古魅力的画面风格,就是像素艺术。如今,这种风格不仅没有过时&a…...

Windows环境下高效批量抓取RPM包的实战指南

1. 为什么要在Windows上批量抓取RPM包? 很多朋友可能觉得奇怪,RPM包不是Linux系统(尤其是Red Hat、CentOS、Fedora这些发行版)专用的软件包格式吗?为什么要在Windows系统上折腾这个?我刚开始接触这个需求时…...

FLUX.1-dev实战分享:如何利用开源模型生成细节丰富的创意视觉内容

FLUX.1-dev实战分享:如何利用开源模型生成细节丰富的创意视觉内容 如果你正在寻找一款能真正理解你想法、并能将复杂创意转化为高质量图像的AI工具,那么FLUX.1-dev绝对值得你花时间深入了解。作为Black Forest Labs推出的开源图像生成模型,它…...

鸿蒙智控节点:基于Hi3861的轻量级物联网边缘执行器设计

1. 项目概述“鸿蒙智控节点”是一个面向物联网边缘控制场景的嵌入式硬件平台,其核心目标是提供一种低功耗、高集成度、可快速部署的无线智能控制终端。该节点并非通用型开发板,而是针对具体物理交互任务(如云台调节、灯具开关、声控触发&…...

Dify私有化部署避坑指南:97%企业踩过的4类网络分段错误、2种认证断链风险与实时熔断配置(含等保三级合规checklist)

第一章:Dify私有化部署的等保三级合规基线与架构定位等保三级(GB/T 22239–2019)对AI应用平台提出明确要求:身份鉴别需双因素认证、访问控制须基于最小权限原则、日志留存不少于180天、敏感数据须加密存储与传输、系统须具备入侵检…...

R语言设备故障预测落地难?揭秘90%工程师忽略的4个数据预处理致命陷阱

第一章:R语言设备故障预测落地难?揭秘90%工程师忽略的4个数据预处理致命陷阱在工业IoT场景中,大量工程师用R构建LSTM或随机森林模型预测设备剩余寿命(RUL),却在生产环境持续遭遇AUC骤降、误报率飙升甚至模型…...

YOLOE实战指南:如何自定义类别名称列表实现零样本迁移

YOLOE实战指南:如何自定义类别名称列表实现零样本迁移 如果你正在寻找一个既能做目标检测又能做实例分割,还能识别任意类别物体的模型,那么YOLOE绝对值得你深入了解。想象一下,你有一个工业质检项目,需要检测“裂纹”…...

5分钟快速体验GTE模型:Colab在线实战指南

5分钟快速体验GTE模型:Colab在线实战指南 想试试阿里达摩院开源的GTE文本向量模型,但又不想折腾本地环境?今天咱们就来个极简体验,用Google Colab在线跑通GTE模型,从安装到出结果,5分钟搞定。 GTE&#x…...

CHORD-X与STM32嵌入式系统联动:边缘计算战术节点设计

CHORD-X与STM32嵌入式系统联动:边缘计算战术节点设计 最近在做一个挺有意思的项目,需要把AI大模型的能力“下沉”到最靠近数据产生的地方。我们尝试用一块小小的STM32单片机,配合一个摄像头,搭建了一个低成本的边缘感知节点。这个…...

小白/程序员入门大模型必看:AI工程师成长路线,告别迷茫快速入场

你是不是也有这种困惑? AI大模型火得一塌糊涂,不管是想转行AI,还是程序员想拓展技能边界,都想分一杯羹,可站在门口却无从下手? 网上的AI教程铺天盖地,刷得越多越焦虑——有人说入门必须先啃高…...

AudioSeal效果展示:同一音频嵌入不同payload(版权ID/时间戳/渠道码)对比效果

AudioSeal效果展示:同一音频嵌入不同payload(版权ID/时间戳/渠道码)对比效果 1. 引言:音频水印的“隐形身份证” 想象一下,你创作了一段精彩的AI语音,发布到网上后,很快被其他人下载、二次剪辑…...

ChatGPT使用技巧:从API调用到生产环境优化的实战指南

在构建基于大语言模型的应用时,直接调用ChatGPT API虽然便捷,但在生产环境中往往会遇到一系列挑战。高延迟、不可预测的token消耗、突发的速率限制(RateLimit)错误以及响应质量的不稳定性,都可能成为系统稳定性和用户体…...

一文说透Native-PAGE

非变性聚丙烯酰胺凝胶电泳(Native-PAGE)或称为活性电泳是在不加入SDS和巯基乙醇等变性剂的条件下,对保持活性的蛋白质进行聚丙烯酰胺凝胶电泳,常用于酶的鉴定、同工酶分析和提纯。与非变性凝胶电泳最大的区别就在于蛋白在电泳过程中和电泳后都不会变性&a…...

外泌体研究解决方案

背景介绍外泌体(exosomes)是一类由细胞分泌到胞外的囊泡,最早由Pan和Johnstone在绵羊网织红细胞中发现并命名。随着研究的深入,人们发现包括血细胞、免疫细胞、癌细胞、干细胞等在内的几乎所有细胞都可以产生外泌体,所产生的外泌体不仅存在于…...

Python3 运算符(上篇)

什么是运算符?本章节主要说明 Python 的运算符。举个简单的例子:4 5 9例子中,4 和 5 被称为操作数, 称为运算符。Python 语言支持以下类型的运算符:算术运算符比较(关系)运算符赋值运算符逻辑运算符位运算符身份运算…...

华为od 面试八股文_C++_09_含答案

目录 1:extern "C" 的作用是什么?为什么要使用它? 2:explicit 关键字有什么用?为什么很多构造函数建议加上它? 3:详细说一下迭代器失效(Iterator Invalidation&#xf…...

第2讲 配置和管理复制拓扑

目录 1.什么是MySQL复制?何时使用MySQL复制? (1)概念 (2)应用场景 【1】水平横向扩展 【2】商业智能与分析 在正式介绍其用途前,我们先理清两个概念---OLTP和OLAP 2.为什么配置复制不能用soc…...

Using Vulkan -- Querying Properties, Extensions, Features, Limits, and Formats -- Enabling Features

本节讲解启用 features 的具体流程。 Category of Features Vulkan 中的所有 feature 可归为 / 查自以下 3 类: Core 1.0 Features 这些是 Vulkan 1.0 初始版本就提供的特性集合。特性列表可在 VkPhysicalDeviceFeatures 中找到。 Future Core Version Feature…...

问题解决方法:铺铜修改后无反应的完整排查与解决步骤

你已经把铜箔 / 内电层到焊盘的间距设为 0,但铺铜仍有间隙,这通常是热焊盘规则或铺铜未重建导致的,按以下步骤逐一解决:1. 先关闭热焊盘(发散连接)热焊盘会刻意在铺铜和引脚间留间隙,这是最常见…...

AI重构医疗生态:从技术赋能到临床革命,未来医疗已至

人工智能正在以一种不可逆的方式,渗透并重塑医疗健康行业。如果说过去几年,AI在医疗领域的应用还停留在影像识别、病历结构化、辅助问诊等单点突破,那么从2025到2026年开始,随着多模态大模型、可解释AI、联邦学习、数字孪生与端侧…...

【 Windows 操作系统】.bat 与 .ps1 的区别和作用

很多人“会用脚本”,但说不清脚本。 真正的差距,往往从 bat 和 ps1 的理解深度 开始拉开。一、为什么 Windows 会同时存在 .bat 和 .ps1?这是一个历史 架构演进的问题。.ps1 是 PowerShell 脚本文件的扩展名,用于编写和执行 Powe…...

Coruna 漏洞工具包曝光:苹果紧急推送 iOS 15.8.7,老 iPhone 正面临一场「无声围剿」

近日,苹果面向仍在使用 iOS 15 的老旧机型,紧急推送 iOS 15.8.7 安全更新,官方描述简短低调,却直指一个代号为 Coruna 的高危漏洞利用工具包。这不是一次常规迭代,而是一场针对数亿旧款 iPhone 的安全止损。 在移动安全…...

RAG技术解析:让大模型从“闭卷考试“到“开卷考试“的进化

RAG(检索增强生成)是一种结合检索与生成的AI架构,通过外挂知识库解决大模型的幻觉、缺乏专业知识和可解释性问题。工作流程分为索引、检索、增强、生成四阶段。企业应用广泛,包括知识助手、智能客服等。未来发展趋势包括GraphRAG、Agent增强RAG和多模态R…...

用大模型和RAG打造智能客服系统,小白也能轻松上手

本文详细介绍了如何利用大模型和RAG技术构建智能客服系统。通过分块处理企业文档、向量化存储和检索知识,系统能够理解用户意图、提供准确回答并支持多轮对话。相比传统客服的慢、笨、贵,该方案可降低70%成本,支持本地部署保障数据安全&#…...

“HALCON error #2404: Invalid handle type in operator do_ocr_multi_class_cnn

"HALCON error #2404: Invalid handle type in operator do_ocr_multi_class_cnn版本不一致的时候,安装群里的halcon20.11...