桌面应用通信【免费下载链接】NearDropAn unofficial Google Nearby Share/Quick Share app for macOS项目地址https://gitcode.com/gh_mirrors/ne/NearDrop点击查看免费下载导读本文以 NearDropmacOS 上的非官方 Google Nearby Share / Quick Share 客户端的 协议文档 为主体完整梳理 Nearby Share 的线缆外协议设备如何通过 mDNS BLE 相互发现、如何通过 UKEY2 SecureMessage 完成端到端加密握手、如何在传输层Nearby Connections与业务层Share双层 Protobuf 嵌套中传输文件。读完本文你将掌握实现一个 Nearby Share 兼容接收端/发送端所需的全部协议细节并能在 NearDrop 仓库 中找到每一步对应的 Swift 源码佐证。协议总览端到端加密的 P2P 传输Nearby Share 是一个点对点peer-to-peer、端到端加密的协议。作者 Grishka 通过阅读 Chromium 源码与反编译 Google Services Framework apk 逆向整理出本协议其整体设计看起来主要面向 UDP 这类不可靠介质但作者只在 TCP 上实际观测过它。协议分为两层传输层Nearby Connections通用的设备发现与连接层负责 mDNS 广播、TCP 连接、加密握手与分块传输业务层Share / Quick Share运行在传输层之上负责传输元数据文件名、类型、大小、接受/拒绝应答等业务语义。这两层都使用 Protobuf 编码且加密后还会再包一层 Protobuf于是出现了protobuf 套 protobuf、再套加密后的 protobuf、又套 protobuf的嵌套结构。NearDrop 已把这些协议文件从 Chromium 源码中收集好位于 NearbyShare/ProtobufSource对应的 Swift 生成代码在 NearbyShare/Protobuf。要实现一个自己的 Nearby Share 客户端你需要四样东西mDNS 实现多数现代操作系统内置如 macOS 的NetService、NWBrowser密码学库支持 ECDSA 密钥交换、AES-CBC、HMAC 与 SHA256OpenSSL 可以但略显臃肿NearDrop 使用 Swift 的 CryptoKit CommonCrypto SwiftECCProtobuf 库NearDrop 使用 Swift Protobuf代码由 GenerateProtobuf.sh 生成上述 Protobuf 源文件。调试时Android 上 Nearby Share 的日志logcat极其详尽遇到问题非常有用——作者在逆向过程中就大量借助了它。设备角色与相互发现角色分工因为文件传输是单向的两个对端被赋予不同角色接收方 服务器server监听一个 TCP 端口并对外广播 mDNS 服务发送方 客户端client发现 mDNS 服务并连接服务器的 TCP 端口。mDNS 广播要让设备出现在 Android 的分享面板里接收方server要广播一个 mDNS 服务参数如下参数取值domain空type_FC9F5ED42C8A._tcp.port服务器接受入站连接的任意 TCP 端口服务**名称name**是下面 10 个字节的 URL-safe Base64 编码偏移内容说明00x23Google 称之为 PCP含义未知1–44 字节endpoint ID4 个随机字母数字字符用于设备间互相标识Android 日志中大量使用5–73 字节service ID0xFC, 0x9F, 0x5ESHA256(NearbySharing)的前 3 字节8–92 个零字节用途未知其中 service ID 的来源是SHA256(NearbySharing) fc9f5ed42c8a5e9e94684076ef3bf938a809c60ad354992b0435aebbdc58b97b取前三个字节fc 9f 5e。NearDrop 中这一逻辑在 NearbyConnectionManager.swift 的initMDNS()中实现用NetService(domain: , type: _FC9F5ED42C8A._tcp., name: name, port: port)发布并通过NetService.data(fromTXTRecord:)设置 TXT 记录endpoint ID 由generateEndpointID()同文件 L233-L240从 62 个字母数字字符中随机取 4 个生成。TXT 记录nendpoint info服务还需要一个键为n的 TXT 记录其值为下述结构的 URL-safe Base64 编码即 endpoint info1 字节位域高 3 位version设为 1 或 0看起来没有区别1 位visibility0 可见中间 3 位device typeAndroid 用它选图标。取值0 unknown1 phone2 tablet3 laptop4 car5 foldable phone6 XR device最低 1 位reserved设为 0。16 字节与设备标识相关但脱离 Google 服务器可能没有意义可以随便填随机数。其内部结构为2 字节salt加密公共证书元数据时使用的随机盐14 字节encrypted metadata key用于加密公共证书元数据的对称密钥含标识远端设备的账户标识符可用 salt 与对应证书的 secret/authenticity key 解密。这实际上是联系人可见性contacts-only机制的离线凭据。用户可见的设备名UTF-8前置 1 字节长度。仅当首字节的 visibility 位为 0 时出现。可选 TLV 记录每条1 字节 type、1 字节 length、length 字节 value。已知类型1QR code 数据详见下文2vendor ID1 字节0 none1 Samsung用途不明。NearDrop 中 EndpointInfo 的serialize()与init?(data:)分别负责 endpoint info 的编码与解析第一字节为deviceType.rawValue 1设备类型左移 1 位visibility 位默认 0 即可见随后 16 字节随机数、1 字节长度前缀的设备名最后循环读取 TLVtype 1 即 QR code 数据。接收连接请求时 InboundNearbyConnection.swift 用同样的字节布局解析出设备类型与名称。BLE 广播与 macOS 的限制Android 并不会无视 visibility 设置始终广播 mDNS而是等待收到特定 BLE 广播后才开始广播。BLE 广播参数如下Service UUID fe 2cService data fc 12 8e 01 42 00 00 00 00 00 00 00 00 00 [10 个随机字节]Android 在搜索 Nearby Share 目标时会周期性发送这种 BLE 广播这也是附近设备正在共享通知弹出device nearby is sharing的触发来源。这段广播无法从 macOS 发出——作者称没有 API 可以设置 service data而 Android 侧硬编码了 service data 前缀匹配因此在 macOS 上确实没有办法走这条自动发现路径。这正是 NearDrop 只能对同一网络上的所有人一直可见的根本原因README.md 的 Limitations 一节也明确提到这一点也是二维码方案存在的原因。二维码配对绕开 BLE 的自动连接二维码内容与密钥派生发送设备可以生成二维码给接收设备扫从而绕过 BLE 广播。二维码内容是一个 URLhttps://quickshare.google/qrcode#keyXXX其中XXX是发送设备 ECDSA 公钥的压缩格式即只取 X 值前面加上 2 字节的版本号 0再另加1 字节的版本号 2 或 3最后做 URL-safe Base64 编码。这个公钥不必与后面连接时使用的公钥一致——可以专门为二维码生成一对独立密钥。双方需要从key参数解码 base64 后、仍包含版本号派生两个密钥派生密钥参数advertising token广播令牌HKDF-SHA256(IKM key参数salt 为空info advertisingContext输出长度 16 字节)name encryption key名称加密密钥HKDF-SHA256(IKM key参数salt 为空info encryptionKey输出长度 16 字节)NearDrop 中 generateQrCodeKey() 完整实现了这一流程生成 EC256r1 密钥对后keyData [0, 0, 2] X 坐标去掉可能的前导零字节作者注明 Android 对此非常挑剔会破坏 endpoint info然后分别以advertisingContext与encryptionKey为 info 做 HKDF 得到 16 字节的 advertising token 与 name encryption key。二维码本身在 ShareViewController.swift 中由 QRCode 库生成文本正是https://quickshare.google/qrcode#key\(qrKey)。接收方扫码后的行为当接收设备扫到二维码更准确地说是处理该 URL 的 activity 启动时它开始广播自己的 mDNS 服务并在 endpoint info 中加入一个 type 1QR codeTLV 记录。该记录内容取决于接收设备的 visibility 设置可见visibleTLV 记录直接包含advertising token原文隐藏hiddenvisibility 位设为 1、不再有明文名称TLV 记录包含用AES-GCM加密的名称。格式为12 字节初始化向量 密文 16 字节认证标签密钥是name encryption key认证附加数据AAD是advertising token。发送方在显示二维码期间会逐个检查发现的设备是否命中任一条件GMS 中的实现是先拿 TLV 记录与advertising token直接比较不匹配再尝试解密。一旦找到匹配设备发送方自动连接它。NearDrop 接收端在 maybeAddFoundDevice 中实现了匹配逻辑先比较qrData qrCodeAdvertisingToken否则若qrData.count 28则尝试用AES.GCM.open(box, using: qrCodeNameEncryptionKey!, authenticating: qrCodeAdvertisingToken!)解密出隐藏设备名成功后通知 Share 扩展自动发起连接。跳过用户确认的签名要跳过用户确认弹窗发送方发出的PairedKeyEncryptionFrame中的qr_code_handshake_data必须是对 UKEY2 auth key即用于派生连接 PIN 的那个密钥的 ECDSA 签名签名私钥对应二维码中使用的公钥。签名采用 IEEE P1363 格式——即R和S两个值直接拼接共 64 字节。NearDrop 发送端在 OutboundNearbyConnection.swift 中实现let signature qrKey.sign(msg: authKey!.data())随后把signature.r与signature.s拼接为qrCodeHandshakeData。作者在文档中留了一个 TODO有时这样做仍然会弹出确认框原因尚未查明。高层时序一次完整的传输协议文档给出了如下时序图从客户端视角用 mermaid 表示这个时序在 NearDrop 中由一对状态机实现接收端 InboundNearbyConnection.swift 的状态依次为initial → receivedConnectionRequest → sentUkeyServerInit → receivedUkeyClientFinish → sentConnectionResponse → sentPairedKeyResult → receivedPairedKeyResult → waitingForUserConsent → receivingFiles发送端 OutboundNearbyConnection.swift 的状态依次为initial → sentUkeyClientInit → sentUkeyClientFinish → sentPairedKeyEncryption → sentPairedKeyResult → sentIntroduction → sendingFiles。两侧相互印证形成完整的协议闭环。帧类型与 TCP 封帧线缆上直接出现的包有三种类型Offline frames离线帧nearby 协议的基本单位用于控制连接连接请求、应答、keep-alive、断开等定义见 offline_wire_formats.protoUKEY2 messages用于加密密钥交换UKEY2 是 Google 自研算法定义见 ukey.protoSecure messages仅在初始协商之后使用以加密形式承载其他包定义见 securemessage.proto。每个通过 TCP 发送的 Protobuf 消息都带4 字节大端MSB 在前长度前缀。NearDrop 在 NearbyConnection.swift 的receiveFrameAsync/sendFrameAsync中实现先收 4 字节解析frameLengthUInt32(content[0]) 24 | ...并校验其不超过SANE_FRAME_LENGTH 5 * 1024 * 10245 MiB以免被异常包打爆内存发送时同样把长度按大端序写入前 4 字节。初始握手与密钥交换以服务器/接收方视角连接请求Connection request客户端连上 TCP 端口后先发两个包一个connection requestoffline frame 子类型和一个UKEY2 client init。connection request 中唯一值得关注的是endpointInfo字段它包含设备类型与名称格式与前面nTXT 记录相同只是没有 base64 编码。此外客户端还会列出自己支持的 mediumsNearDrop 只支持wifiLan见 OutboundNearbyConnection.swift。ConnectionRequestFrame.Medium枚举在 offline_wire_formats.proto 中列出了BLUETOOTH、WIFI_HOTSPOT、BLE、WIFI_LAN、WIFI_AWARE、NFC、WIFI_DIRECT、WEB_RTC、BLE_L2CAP、USB、AWDL等全部介质。UKEY2 client init这是 UKEY2 消息的子类型是端到端加密密钥交换的起始步。Google 的 UKEY2 参考实现是开源的细节请参考该仓库。收到 client init 后服务器生成一个 ECDSA 密钥对在server init中发出自己的公钥。服务器还需记住原始序列化的 client init 消息用于最终密钥派生而即将发出的 server init 消息本身也用于下一步。注意这些字节包含整个 Protobuf 消息不含 int32 长度前缀。UKEY2 client finish客户端收到 server init 后完成密钥派生并发回client finish内含其公钥。服务器在这一步完成密钥派生。密钥交换的结果是两个值authentication string认证字符串与next protocol secret下一协议密钥。next protocol secret经过进一步处理得到用于后续通信加密与认证的两组 32 字节 AES 与 32 字节 HMAC 密钥先派生两个 32 字节 device to deviceD2D密钥HKDF-SHA256密钥IKMsaltinfoD2D client keynext protocol secret82AA55A0D397F88346CA1CEE8D3909B95F13FA7DEB1D4AB38376B8256DA85510即SHA256(D2D)clientD2D server key同上同上server再派生用于实际加密的四个密钥四个都用同一个 saltSHA256(SecureMessage) BF9D2A53C63616D75DB0A7165B91C1EF73E537F2427405FA23610A4BE657642E。注意这些密钥是从服务器server视角命名的如果你是客户端需要把它们对调解密/接收用 server key加密/发送用 client key密钥IKMinfoDecrypt key解密D2D client keyENC:2Receive HMAC key接收校验D2D client keySIG:1Encrypt key加密D2D server keyENC:2Send HMAC key发送签名D2D server keySIG:1NearDrop 中 finalizeKeyExchange 逐字实现了上述全部派生ECDH 得到共享秘密后 SHA256 之再用 saltUKEY2 v1 auth/UKEY2 v1 next、info 为 client-initserver-init 拼接体分别 HKDF 出 auth string 与 next secret随后按文档中的 salt/info 依次派生出 D2D client/server key 与四个加解密密钥最后根据isServer()决定四把钥匙的归属服务器视角 vs 客户端视角的交换。authentication string用于带外密钥验证。Nearby Share不使用UKEY2 规定的算法而是用 Chromium 源码中的算法生成一个4 位 PIN 码。NearDrop 的 pinCodeFromAuthKey 实现了该算法对 auth key 的每个字节计算hash (hash byte * multiplier) % 9973、multiplier (multiplier * 31) % 9973最后输出abs(hash)的 4 位十进制。连接应答Connection response密钥交换完成后服务器与客户端互发最后一个明文消息connection responseoffline frame 子类型表示对方已接受连接。此后所有通信都加密并包裹在 payload 层中。NearDrop 中服务器在 processConnectionResponseFrame 里回复response .accept并把osInfo.type .apple同时置encryptionDone true客户端在 processUkey2ServerInit 中发送 client finish 后同样发送 connection response 并置encryptionDone true。加密层SecureMessage线缆上的消息类型始终是 secure message它有两个字段header_and_body与signature。header_and_body是序列化后的HeaderAndBody消息内部又是两个字段header 与 body。body 是加密后的载荷header 包含encryption scheme加密方案必须为AES256_CBCsignature scheme签名方案必须为HMAC_SHA256IV16 字节随机数用于 AES-CBCpublic metadata公共元数据协议可扩展性所需含两个常量字段——version 恒为 1、type 恒为DEVICE_TO_DEVICE_MESSAGE见 securegcm.proto 的GcmMetadata。signature是 header-and-body 字段用上面派生的某个密钥做的 HMAC-SHA256。body用 AES-CBC PKCS7 填充加密解密后应得到一个合法的 device to device message见 securegcm.proto 的DeviceToDeviceMessage。若不是说明实现有误需要回去调试密钥交换代码——文档作者调侃道密码学很乱别担心没人第一次就能写对。DeviceToDeviceMessage包含一个序列号sequence number与一个消息messagemessage 永远是序列化后的 offline frame。序列号从 1 开始、每条消息递增客户端与服务器各自维护独立的序列号。NearDrop 中 encryptAndSendOfflineFrame 与 decryptAndProcessReceivedSecureMessage 是加密层的实现发送侧用CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, encryptKey, kCCKeySizeAES256, ...)加密、构造HeaderAndBodyscheme 为.aes256Cbc、signature scheme 为.hmacSha256、public metadata 为 version1 / type.deviceToDeviceMessage 的GcmMetadata并用HMACSHA256对 header-and-body 做签名接收侧先比对 HMAChmac smsg.signature再解密 body反序列化DeviceToDeviceMessage后严格校验序列号d2dMsg.sequenceNumber clientSeq见 L259-L260最后按 offline frame 的类型分发处理。载荷层分块传输任意大小的数据这一层允许以分块chunk形式传输任意大小的载荷。载荷分两种类型bytes与file。所有协商消息都用 bytes 载荷承载 Protobuf 消息实际文件用 file 载荷。载荷传输帧PayloadTransferFrame会被包进类型为PAYLOAD_TRANSFER的 offline frame再按上文方式加密。各字段含义如下header元数据id连接内的载荷标识符允许并行传输多个载荷用它跟踪多个传输、关联缓冲区/文件等typeBYTES或FILEproto 中还定义了STREAM见 offline_wire_formats.proto 的PayloadHeader.PayloadTypetotalSize总大小不言自明chunk数据本身offset该块需要写入缓冲区或文件的偏移量flags若设置LAST_CHUNKbit 0表示传输完成、这是最后一块body数据字节。一个值得注意的实现细节Android 对每条协商消息都会连续发送 2 个 payload transfer 帧——第一个含完整消息第二个含 0 字节但置LAST_CHUNK标志。NearDrop 复刻了这一行为sendBytesPayload 先发一个offset0, flags0, body完整数据的帧再发一个offset数据长度, flags1(LAST_CHUNK), body空的帧。而真正传输文件时sendNextFileChunk 按 512 KiB512*1024分块读取文件每块一个 payload transfer 帧文件末尾再补一个flags1的 EOF 帧——代码注释调侃道是的这一切就为了一个 bit。接收侧 processFileChunk 会校验块偏移与文件大小防止超出声明大小写入FileHandle并更新Progressbytes 载荷则在 decryptAndProcessReceivedSecureMessage 中按id汇聚到payloadBuffers校验chunk.offset buffer.count不允许乱序/跳号收到LAST_CHUNK后交给processBytesPayload解析出内层的Sharing_Nearby_Frame。Paired key encryption含义不明的握手客户端与服务器互发一个paired key encryption帧包裹在 payload 层里。文档推测它用于所有可见性限制的号码phone number相关机制而获取其中数据可能涉及与 Google 服务器通信。作者发送的帧里secretIDHash设为 6 个随机字节、signedData设为 72 个随机字节工作正常。随后双方互发paired key result帧双方的status都设为UNABLE。NearDrop 的实现与文档完全一致服务器与客户端都构造PairedKeyEncryptionFramesecretIDHash Data.randomData(length: 6)、signedData Data.randomData(length: 72)InboundNearbyConnection.swift、OutboundNearbyConnection.swift结果帧PairedKeyResultFrame.status .unable。这些帧以及后续帧的定义在 wire_format.protoPairedKeyEncryptionFrame含signed_data、secret_id_hash、optional_signed_data、qr_code_handshake_data四个字段PairedKeyResultFrame.Status含SUCCESS / FAIL / UNABLE。传输元数据introduction成功交换无意义的 paired key encryption 帧后客户端向服务器发送一个introduction帧包含即将发送的文件列表。字段含义自明FileMetadata含name人类可读文件名、typeIMAGE/VIDEO/ANDROID_APP/AUDIO/DOCUMENT/CONTACT_CARD见 wire_format.proto、payload_id后续在 payload 层传输该文件的载荷 ID、size、mime_type等。IntroductionFrame还可携带TextMetadata、WifiCredentialsMetadata、AppMetadata、StreamMetadata等其他附件元数据。此刻 Android 显示连接成功并展示 PIN 码服务器弹出提示询问用户是否接受传输。NearDrop 中发送端在 processPairedKeyResult 里根据要发送的 URL 构建FileMetadata通过 UTType 推断 mimeType进而映射到IMAGE/VIDEO/AUDIO/ANDROID_APP/UNKNOWN类型文件名经sanitizeFileName清洗非法字符或TextMetadataURL 分享场景接收端在 processIntroductionFrame 中解析文件/文本元数据为文件预分配InternalFileInfo与目标路径重名时自动追加(1)、(2)等后缀见makeFileDestinationURL然后通过 delegate 回调请求用户确认含 PIN 码。文件传输接受与拒绝接受服务器发送status ACCEPT的 response 帧后客户端开始通过 payload 层发送文件分块。NearDrop 中 acceptTransfer 会先为每个文件创建空文件与FileHandle、发布带totalUnitCount的Progress再发送ConnectionResponseFrame(status: .accept)并进入receivingFiles状态。拒绝同样发 response 帧但status REJECT。此外还有其他状态码如NOT_ENOUGH_SPACEAndroid 会据此显示不同错误。完整的枚举在 wire_format.protoUNKNOWN / ACCEPT / REJECT / NOT_ENOUGH_SPACE / UNSUPPORTED_ATTACHMENT_TYPE / TIMED_OUT。NearDrop 的 rejectTransfer 支持reject与unsupportedAttachmentType两种原因发送端 processConsent 对reject/unknown、notEnoughSpace、timedOut、unsupportedAttachmentType分别映射到不同的NearbyError.canceled(reason:)错误码并断开连接。Keep-alive 保活帧Android 每10 秒发送一次类型为KEEP_ALIVE的 offline frame并期望服务器同样回复若不回复一段时间后 Android 会认为应用崩溃而终止连接。这在传输大文件时尤其重要——TCP 内建确认是不够的因为抽象层太多设计者反而忘了这回事。协议文档原话是No, TCPs built-in acknowledgements are not enough. There are so many abstraction layers that whoever came up with this forgot about them.NearDrop 在 decryptAndProcessReceivedSecureMessage 中收到KEEP_ALIVE帧时立即调用 sendKeepAlive(ack: true) 回一个带ack标志的 keep-alive 帧加密已建立则走加密通道。KeepAliveFrame的定义见 offline_wire_formats.proto含ack与seq_num两个字段。传输介质mediums与带宽升级Nearby ConnectionsNearby Share 的底层支持运行在不同的介质mediums上。Wi-Fi LAN 是其中之一Bluetooth、BLE、Wi-Fi Direct 等是其他介质。介质的选择权在服务器客户端在自己的connection request包里声明支持的介质服务器再与自己的介质集合求交集。传输被接受后服务器可能通过发送一个含所选介质与认证凭据如有的包向客户端请求带宽升级bandwidth upgrade。但实际的介质切换机制至今仍不清楚。对应的BandwidthUpgradeNegotiationFrame定义在 offline_wire_formats.proto包含UPGRADE_PATH_AVAILABLE、LAST_WRITE_TO_PRIOR_CHANNEL、SAFE_TO_CLOSE_PRIOR_CHANNEL、CLIENT_INTRODUCTION、UPGRADE_FAILURE等事件类型以及UpgradePathInfo中每种介质WifiHotspot、WifiLanSocket、Bluetooth、WifiAware、WifiDirect、WebRtc、Awdl各自的凭据结构。从该 proto 可推断介质切换是一个多阶段握手流程但 NearDrop 只实现 Wi-Fi LAN因此未实际参与。总结与实现清单从 PROTOCOL.md 与 NearDrop 源码的对照来看一个可工作的 Nearby Share 兼容实现至少需要打通以下环节发现作为接收方广播_FC9F5ED42C8A._tcp.mDNS 服务10 字节名称 nTXT 记录作为发送方用 mDNS 浏览器发现并解析 endpoint infoNearbyConnectionManager.swift连接4 字节大端长度前缀 connection request / connection response 明文帧密钥交换UKEY2 client init / server init / client finish 三轮握手派生出 4 个 32 字节 AES/HMAC 密钥与 4 位 PINNearbyConnection.swift加密通信AES-256-CBC PKCS7 HMAC-SHA256 的 SecureMessage 包装序列号校验NearbyConnection.swift协商paired key encryption/result随机字节即可 introduction 元数据 response 接受/拒绝传输bytes/file 载荷分块LAST_CHUNK标志结束keep-alive 保活。每一步都能在 NearbyShare 目录的源码与 NearbyShare/ProtobufSource 的 proto 定义中找到对应实现。如果你打算从零实现自己的 Nearby Share 客户端这套文档 源码组合是目前最直接、最完整的公开参考资料。赞分享桌面应用通信【免费下载链接】NearDropAn unofficial Google Nearby Share/Quick Share app for macOS项目地址https://gitcode.com/gh_mirrors/ne/NearDrop点击查看免费下载相关推荐从零训练OpenLane-V2基线模型完整训练、评估与可视化流程从零训练OpenLane V2基线模型完整训练、评估与可视化流程 OpenLane V2 是 NeurIPS 2023 发布的全球首个面向自动驾驶场景结构感知自动驾驶人工智能模型评测计算机视觉数据集AzerothCore-WoTLK 地图数据提取完整指南map/vmap/mmaps 一次跑通AzerothCore WoTLK 地图数据提取完整指南map/vmap/mmaps 一次跑通 搭 WoTLK 私服的人大多被卡死在同一步服务端起来了世界游戏开发后端OliveTin快速入门5分钟内搭建你的第一个Web操作面板OliveTin快速入门5分钟内搭建你的第一个Web操作面板 OliveTin是一款开源、轻量级的Web界面工具让你能够安全、简单地通过网页访问和执行预定义运维后端上一篇Qwen3.8-Flash-Next 模型解析与实战部署指南混合注意力架构、N-gram 嵌入与长上下文推理下一篇SoL-Pi兼容与部署完全参考如何选对并验证Pi版本创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考