腾讯云日志服务(CLS)提供网络探测 SDK 插件(iOS 版),集成后可主动发起 HTTP Ping、DNS、Ping、MTR、TCP Ping 等网络诊断探测,探测数据将自动上报至 CLS,帮助实时掌握终端用户的网络质量状况,快速定位网络问题。
前提条件
创建并获取云 API 密钥信息 SecretId 和 SecretKey,密钥信息获取请前往 API 密钥管理。
已在 CLS 控制台获取移动端接入 Token,详见 获取密钥。
集成步骤
步骤1:集成插件
方式一:CocoaPods(推荐)
1. 修改 CocoaPods 的配置文件 Podfile。
仅日志上报功能:
platform :ios, '12.0'use_frameworks!target 'YourApp' dopod 'TencentCloudLogProducer/Core', '~> 3.1.0'end
需要日志上报和网络诊断功能(完整功能):
platform :ios, '12.0'use_frameworks!target 'YourApp' dopod 'TencentCloudLogProducer/NetWorkDiagnosis', '~> 3.1.0'end
2. 打开终端,执行安装命令。
pod install
方式二:手动集成
1. 从 GitHub Releases 下载最新版本。
2. 将
TencentCloudLogProducer 文件夹拖入 Xcode 工程。并勾选 Copy items if needed 和 Create groups。3. 添加依赖。手动添加以下依赖库:
Protobuf (~> 3.29.5)
FMDB (~> 2.7.5)
Reachability (~> 3.7)
4. 配置系统库。在 Build Phases → Link Binary With Libraries 中添加:
Foundation.framework
SystemConfiguration.framework
UIKit.framework
CoreTelephony.framework(网络诊断)
Network.framework(网络诊断)
libz.tbd
libsqlite3.tbd
libresolv.tbd(网络诊断)
步骤2:初始化配置
// 1. 配置日志上报ClsLogSenderConfig *config = [ClsLogSenderConfig configWithEndpoint:@"ap-guangzhou-open.cls.tencentcs.com"accessKeyId:@"YOUR_ACCESS_KEY_ID"accessKey:@"YOUR_ACCESS_KEY"];// 2. 初始化网络诊断(使用 netToken)NSString *netToken = @"YOUR_NET_TOKEN"; // Base64 编码的 JSON,包含 networkAppId/appKey/topic_id[[ClsNetworkDiagnosis sharedInstance] setupLogSenderWithConfig:confignetToken:netToken];// 3. 设置全局扩展字段(可选)[[ClsNetworkDiagnosis sharedInstance] setUserEx:@{@"scene": @"homepage"}];
网络诊断
网络诊断模块提供5种探测方式,帮助分析应用的网络性能和质量问题。
HTTP Ping
测量 HTTP/HTTPS 请求的完整生命周期,包含15个时间点:DNS 解析、TCP 连接、SSL 握手、请求发送、响应接收等。
基本用法
// 创建请求CLSHttpRequest *request = [[CLSHttpRequest alloc] init];request.domain = @"https://cloud.tencent.com"; // 完整 URLrequest.appKey = @"YOUR_APP_KEY";request.maxTimes = 3; // 探测 3 次request.timeout = 10000; // 超时 10 秒// 执行探测[[ClsNetworkDiagnosis sharedInstance] httpingv2:request complate:^(CLSResponse *response) {if (response.success) {NSLog(@"HTTP Ping 成功");NSLog(@"结果: %@", response.content); // JSON 格式// 解析结果NSDictionary *data = response.data;NSDictionary *netOrigin = data[@"netOrigin"];NSNumber *dnsTime = netOrigin[@"dns_time"]; // DNS 耗时(毫秒)NSNumber *tcpConnectTime = netOrigin[@"tcp_connect_time"]; // TCP 连接耗时NSNumber *sslHandshakeTime = netOrigin[@"ssl_handshake_time"]; // SSL 握手耗时NSNumber *totalTime = netOrigin[@"total_time"]; // 总耗时NSLog(@"DNS: %@ms, TCP: %@ms, SSL: %@ms, 总计: %@ms",dnsTime, tcpConnectTime, sslHandshakeTime, totalTime);} else {NSLog(@"HTTP Ping 失败: %@", response.errorMessage);}}];
高级配置
CLSHttpRequest *request = [[CLSHttpRequest alloc] init];request.domain = @"https://api.example.com/health";request.appKey = @"YOUR_APP_KEY";request.maxTimes = 5;request.timeout = 15000;// 多网卡探测(WiFi + 蜂窝网络并发)request.enableMultiplePortsDetect = YES;// 扩展字段(自定义业务标识)request.detectEx = @{@"api_name": @"/health",@"request_id": @"req_12345"};// 页面名称(用于分组统计)request.pageName = @"HomePage";// 追踪 ID(关联多个探测)request.traceId = [[NSUUID UUID] UUIDString];// SSL 证书验证(默认开启)request.enableSSLVerification = YES;[[ClsNetworkDiagnosis sharedInstance] httpingv2:request complate:^(CLSResponse *response) {// 处理结果}];
HTTP 生命周期时间点
时间点 | 字段名 | 说明 |
1 | callStart | 开始调用 |
2 | dnsStart | DNS 解析开始 |
3 | dnsEnd | DNS 解析结束 |
4 | connectStart | TCP 连接开始 |
5 | secureConnectStart | SSL 握手开始 |
6 | secureConnectEnd | SSL 握手结束 |
7 | connectionAcquired | TCP 连接建立 |
8 | requestHeaderStart | 请求头发送开始 |
9 | requestHeaderEnd | 请求头发送结束 |
10 | requestBodyStart | 请求体发送开始 |
11 | requestBodyEnd | 请求体发送结束 |
12 | responseHeadersStart | 响应头接收开始 |
13 | responseHeaderEnd | 响应头接收结束 |
14 | responseBodyStart | 响应体接收开始 |
15 | responseBodyEnd | 响应体接收结束 |
说明:
时间计算示例:
DNS 耗时 =
dnsEnd - dnsStartTCP 连接耗时 =
connectionAcquired - connectStartSSL 握手耗时 =
secureConnectEnd - secureConnectStart总耗时 =
responseBodyEnd - callStartTCP Ping
测量 TCP 三次握手的延迟,适合测试特定端口的连通性。
// 创建请求CLSTcpRequest *request = [[CLSTcpRequest alloc] init];request.domain = @"cloud.tencent.com";request.appKey = @"YOUR_APP_KEY";request.port = 443; // HTTPS 端口request.maxTimes = 10; // 探测 10 次request.timeout = 5000; // 超时 5 秒// 执行探测[[ClsNetworkDiagnosis sharedInstance] tcpPingv2:request complate:^(CLSResponse *response) {if (response.success) {NSDictionary *data = response.data;NSDictionary *netOrigin = data[@"netOrigin"];NSNumber *latencyMin = netOrigin[@"latency_min"]; // 最小延迟(毫秒)NSNumber *latencyMax = netOrigin[@"latency_max"]; // 最大延迟NSNumber *latencyAvg = netOrigin[@"latency_avg"]; // 平均延迟NSNumber *successCount = netOrigin[@"success_count"]; // 成功次数NSNumber *failureCount = netOrigin[@"failure_count"]; // 失败次数NSLog(@"TCP Ping 统计: 最小=%@ms, 平均=%@ms, 最大=%@ms, 成功=%@, 失败=%@",latencyMin, latencyAvg, latencyMax, successCount, failureCount);} else {NSLog(@"TCP Ping 失败: %@", response.errorMessage);}}];
常用端口:
服务 | 端口 |
HTTP | 80 |
HTTPS | 443 |
MySQL | 3306 |
Redis | 6379 |
MongoDB | 27017 |
SSH | 22 |
SMTP | 25 |
DNS | 53 |
ICMP Ping
使用 ICMP 协议测量网络延迟和丢包率,适合网络质量评估。
基本用法
// 创建请求CLSPingRequest *request = [[CLSPingRequest alloc] init];request.domain = @"cloud.tencent.com";request.appKey = @"YOUR_APP_KEY";request.maxTimes = 10; // Ping 10 次request.size = 64; // 包大小 64 字节request.interval = 200; // 间隔 200msrequest.timeout = 10000; // 超时 10 秒// 执行探测[[ClsNetworkDiagnosis sharedInstance] pingv2:request complate:^(CLSResponse *response) {if (response.success) {NSDictionary *data = response.data;NSDictionary *netOrigin = data[@"netOrigin"];NSNumber *latencyMin = netOrigin[@"latency_min"]; // 最小延迟(毫秒)NSNumber *latencyMax = netOrigin[@"latency_max"]; // 最大延迟NSNumber *latencyAvg = netOrigin[@"latency_avg"]; // 平均延迟NSNumber *latencyStddev = netOrigin[@"latency_stddev"]; // 标准差NSNumber *lossRate = netOrigin[@"loss_rate"]; // 丢包率(百分比)NSLog(@"Ping 统计: 延迟=%@/%@/%@ms, 抖动=%@ms, 丢包率=%@%%",latencyMin, latencyAvg, latencyMax, latencyStddev, lossRate);} else {NSLog(@"Ping 失败: %@", response.errorMessage);}}];
IP 协议偏好控制(v3.0.0新增)
CLSPingRequest *request = [[CLSPingRequest alloc] init];request.domain = @"www.qq.com";request.appKey = @"YOUR_APP_KEY";request.maxTimes = 5;// 设置 IP 协议偏好request.prefer = -1; // -1: 自动检测(默认)// 0: IPv4 优先// 1: IPv6 优先// 2: 仅 IPv4// 3: 仅 IPv6[[ClsNetworkDiagnosis sharedInstance] pingv2:request complate:^(CLSResponse *response) {if (response.success) {NSDictionary *netOrigin = response.data[@"netOrigin"];NSString *hostIp = netOrigin[@"host_ip"]; // 实际使用的 IP 地址NSLog(@"使用 IP: %@", hostIp);}}];
DNS 解析
查询域名的 DNS 记录(A 记录/AAAA 记录),支持自定义 DNS 服务器。
基本用法
// 创建请求CLSDnsRequest *request = [[CLSDnsRequest alloc] init];request.domain = @"cloud.tencent.com";request.appKey = @"YOUR_APP_KEY";request.timeout = 5000; // 超时 5 秒// 执行解析[[ClsNetworkDiagnosis sharedInstance] dns:request complate:^(CLSResponse *response) {if (response.success) {NSDictionary *data = response.data;NSDictionary *netOrigin = data[@"netOrigin"];// 解析结果(JSON 数组)NSString *answerSection = netOrigin[@"answer_section"];NSLog(@"DNS 解析结果: %@", answerSection);/*示例输出:[{"name":"cloud.tencent.com","type":"A","ttl":300,"data":"203.205.158.53"},{"name":"cloud.tencent.com","type":"AAAA","ttl":300,"data":"2408:871a:2100:15::53"}]*/} else {NSLog(@"DNS 解析失败: %@", response.errorMessage);}}];
自定义 DNS 服务器
CLSDnsRequest *request = [[CLSDnsRequest alloc] init];request.domain = @"cloud.tencent.com";request.appKey = @"YOUR_APP_KEY";// 使用公共 DNS 服务器request.nameServer = @"8.8.8.8"; // Google DNS// request.nameServer = @"1.1.1.1"; // Cloudflare DNS// request.nameServer = @"119.29.29.29"; // DNSPod DNS// IP 协议偏好request.prefer = 0; // 0: A 记录优先, 1: AAAA 记录优先[[ClsNetworkDiagnosis sharedInstance] dns:request complate:^(CLSResponse *response) {// 处理结果}];
MTR 路由跟踪
追踪数据包到目标主机的完整路径,包含每一跳的延迟和丢包率。
// 创建请求CLSMtrRequest *request = [[CLSMtrRequest alloc] init];request.domain = @"cloud.tencent.com";request.appKey = @"YOUR_APP_KEY";request.maxTTL = 30; // 最大跳数 30request.protocol = @"icmp"; // 协议:icmp / udprequest.timeout = 60000; // 超时 60 秒(路由跟踪耗时长)// 执行探测[[ClsNetworkDiagnosis sharedInstance] mtr:request complate:^(CLSResponse *response) {if (response.success) {NSDictionary *data = response.data;NSDictionary *netOrigin = data[@"netOrigin"];// 路径信息(JSON 数组)NSString *pathDetail = netOrigin[@"path_detail"];NSLog(@"路由路径: %@", pathDetail);/*示例输出:[{"hop":1,"ip":"192.168.1.1","latency":2.5,"latency_min":2.0,"latency_max":3.0,"loss":0,"responseNum":3},{"hop":2,"ip":"10.0.0.1","latency":10.2,"latency_min":8.5,"latency_max":12.0,"loss":0,"responseNum":3},{"hop":3,"ip":"203.205.158.1","latency":25.8,"latency_min":24.0,"latency_max":28.0,"loss":10,"responseNum":2},...]*/} else {NSLog(@"❌ MTR 失败: %@", response.errorMessage);}}];
协议选择说明
协议 | 说明 | 适用场景 |
ICMP | 使用 ICMP Echo Request 协议 | 测量结果更准确,但可能被防火墙拦截 |
UDP | 使用 UDP 数据包 | 穿透性更好,适合被 ICMP 拦截的网络环境 |
IP 协议偏好控制
本 SDK 的 v3.0.0版本新增 prefer 参数,支持 IPv4/IPv6 协议偏好设置。
prefer 参数说明
值 | 说明 | 适用场景 |
-1 | 自动检测(默认值) | 由系统决定,优先使用双栈网络支持的协议 |
0 | IPv4 优先 | 双栈环境下优先使用 IPv4,IPv4不可用时使用 IPv6 |
1 | IPv6 优先 | 双栈环境下优先使用 IPv6,IPv6不可用时使用 IPv4 |
2 | IPv4 only | 仅使用 IPv4,IPv6地址会被忽略 |
3 | IPv6 only | 仅使用 IPv6,IPv4地址会被忽略 |
使用示例
// 示例 1: 强制使用 IPv4(适用于纯 IPv4 环境)CLSPingRequest *request = [[CLSPingRequest alloc] init];request.domain = @"www.qq.com";request.appKey = @"YOUR_APP_KEY";request.prefer = 2; // IPv4 only[[ClsNetworkDiagnosis sharedInstance] pingv2:request complate:^(CLSResponse *response) {// 只会 Ping IPv4 地址:203.205.158.53}];// 示例 2: 仅查询 IPv6 DNS 记录CLSDnsRequest *request = [[CLSDnsRequest alloc] init];request.domain = @"www.qq.com";request.appKey = @"YOUR_APP_KEY";request.prefer = 3; // IPv6 only - 仅返回 AAAA 记录[[ClsNetworkDiagnosis sharedInstance] dns:request complate:^(CLSResponse *response) {// ANSWER-SECTION: [{"type": "AAAA", "data": "2408:871a:2100:15::53"}]}];// 示例 3: IPv6 优先(双栈环境)CLSMtrRequest *request = [[CLSMtrRequest alloc] init];request.domain = @"cloud.tencent.com";request.appKey = @"YOUR_APP_KEY";request.prefer = 1; // IPv6 优先request.protocol = @"icmp";[[ClsNetworkDiagnosis sharedInstance] mtr:request complate:^(CLSResponse *response) {// 优先追踪 IPv6 路径,失败时自动降级到 IPv4}];
支持 prefer 参数的探测类型
探测类型 | 支持 prefer | 说明 |
HTTP Ping | 不支持 | URL 已指定协议 |
TCP Ping | 不支持 | 直接指定 IP 或域名 |
ICMP Ping | 支持 | 支持 IPv4/IPv6协议选择 |
DNS 解析 | 支持 | 支持 A/AAAA 记录查询控制 |
MTR 路由跟踪 | 支持 | 支持 IPv4/IPv6路径跟踪 |