移动端 IP 优选方案

简介: 无论是从 Local DNS 解析域名,获取到 IP 列表,还是从第三方的 DNS 解析服务中,获取到域名对应的 IP 列表。我们获得多个 IP 后,总是想选取一个最优的 IP 使用,本文主要探讨如何在客户端探测 IP 的连接性以及连接速度,保证返回可用性最好的IP,以达到“IP优选”的目的。

移动端 IP 优选方案

1. IP 优选目的

无论是从 Local DNS 解析域名,获取到 IP 列表,还是从第三方的 DNS 解析服务中,获取到域名对应的 IP 列表。我们获得多个 IP 后,总是想选取一个最优的 IP 使用,本文主要探讨如何在客户端探测 IP 的连接性以及连接速度,保证返回可用性最好的IP,以达到“IP优选”的目的。

2. 新浪开源的 httpdns 的 sdk 里的测速逻辑

新浪开源一个 HTTPDNSLib ,里面包含了测速逻辑,GitHub地址如下:

我们以该 sdk 里的测速逻辑为例进行原理解析。

3. IP 测试实现原理

使用 linux socket connect 和 select 函数实现的。 基于以下原理:

  1. 即使套接口是非阻塞的。如果连接的服务器在同一台主机上,那么在调用connect 建立连接时,连接通常会立即建立成功,我们必须处理这种情况。
  2. 源自Berkeley的实现(和Posix.1g)有两条与select 和非阻塞IO相关的规则:
    A. 当连接建立成功时,套接口描述符变成可写;

B. 当连接出错时,套接口描述符变成既可读又可写。

详细的测速实现如下,原理参考注释:

以 iOS 实现为例:

- (int)testSpeedOf:(NSString *)ip port:(int16_t)port {
   NSString *oldIp = ip;
   //request time out
   float rtt = 0.0;
   //sock:将要被设置或者获取选项的套接字。
   int s = 0;
   struct sockaddr_in saddr;
   saddr.sin_family = AF_INET;
   // MARK: - 设置端口,这里需要根据需要自定义,默认是80端口。
   saddr.sin_port = htons(port);
   saddr.sin_addr.s_addr = inet_addr([ip UTF8String]);
   //saddr.sin_addr.s_addr = inet_addr("1.1.1.123");
   if( (s=socket(AF_INET, SOCK_STREAM, 0)) < 0) {
       NSLog(@"ERROR:%s:%d, create socket failed.",__FUNCTION__,__LINE__);
       return 0;
   }
   NSDate *startTime = [NSDate date];
   NSDate *endTime;
   //为了设置connect超时 把socket设置称为非阻塞
   int flags = fcntl(s, F_GETFL,0);
   fcntl(s,F_SETFL, flags | O_NONBLOCK);
   //对于阻塞式套接字,调用connect函数将激发TCP的三次握手过程,而且仅在连接建立成功或者出错时才返回;
   //对于非阻塞式套接字,如果调用connect函数会之间返回-1(表示出错),且错误为EINPROGRESS,表示连接建立,建立启动但是尚未完成;
   //如果返回0,则表示连接已经建立,这通常是在服务器和客户在同一台主机上时发生。
   int i = connect(s,(struct sockaddr*)&saddr, sizeof(saddr));
   if(i == 0) {
       //建立连接成功,返回rtt时间。 因为connect是非阻塞,所以这个时间就是一个函数执行的时间,毫秒级,没必要再测速了。
       close(s);
       return 1;
   }
   struct timeval tv;
   int valopt;
   socklen_t lon;
   tv.tv_sec = HTTPDNS_SOCKET_CONNECT_TIMEOUT;
   tv.tv_usec = 0;
   
   fd_set myset;
   FD_ZERO(&myset);
   FD_SET(s, &myset);
   
   // MARK: - 使用select函数,对套接字的IO操作设置超时。
   /**
    select函数
    select是一种IO多路复用机制,它允许进程指示内核等待多个事件的任何一个发生,并且在有一个或者多个事件发生或者经历一段指定的时间后才唤醒它。
    connect本身并不具有设置超时功能,如果想对套接字的IO操作设置超时,可使用select函数。
    **/
   int maxfdp = s+1;
   int j = select(maxfdp, NULL, &myset, NULL, &tv);
   
   if (j == 0) {
       NSLog(@"INFO:%s:%d, test rtt of (%@) timeout.",__FUNCTION__,__LINE__, oldIp);
       rtt = HTTPDNS_SOCKET_CONNECT_TIMEOUT_RTT;
       close(s);
       return rtt;
   }
   
   if (j < 0) {
       NSLog(@"ERROR:%s:%d, select function error.",__FUNCTION__,__LINE__);
       rtt = 0;
       close(s);
       return rtt;
   }
   
   /**
    对于select和非阻塞connect,注意两点:
    [1] 当连接成功建立时,描述符变成可写; [2] 当连接建立遇到错误时,描述符变为即可读,也可写,遇到这种情况,可调用getsockopt函数。
    **/
   lon = sizeof(int);
   //valopt 表示错误信息。
   // MARK: - 测试核心逻辑,连接后,获取错误信息,如果没有错误信息就是访问成功
   /*!
    * //getsockopt函数可获取影响套接字的选项,比如SOCKET的出错信息
    * (get socket option)
    */
   getsockopt(s, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon);
   //如果有错误信息:
   if (valopt) {
       NSLog(@"ERROR:%s:%d, select function error.",__FUNCTION__,__LINE__);
       rtt = 0;
   } else {
       endTime = [NSDate date];
       rtt = [endTime timeIntervalSinceDate:startTime] * 1000;
   }
   close(s);
   return rtt;
}

目前 《阿里云 HTTPDNS SDK 》 内部已经集成了该逻辑,如果有兴趣可以进钉钉群交流:"【客服群】阿里云移动服务-HTTPDNS",群号:11777313。

相关文章
|
文字识别 安全 JavaScript
6款超实用的Edge浏览器插件,让你的浏览器瞬间开挂!
Microsoft Edge是由微软开发的一款网页浏览器,致力于提供一个现代化、高效率、安全可靠的网络浏览器,以满足用户对于网络浏览的各种需求。
1140 1
|
文字识别 iOS开发 MacOS
ABBYY FineReader15版本授权许可证 免费OCR图文识别软件
ABBYY FineReader是市场领先的OCR图文识别软件,不仅可以将纸质文档和PDF文件以及图像文件转换成可搜索、可编辑的文本格式,还支持多国文字识别和彩色文件识别,并且能够完整保留原始文本的布局和格式,是日常办公的绝佳帮手。
4643 0
|
3月前
|
安全 小程序 数据建模
阿里云SSL证书最新免费版与收费版对比解析、收费标准详览及申请部署流程指南
本文详细解析了阿里云SSL证书的概览、免费版与收费版的对比、2026年最新收费标准,以及免费版证书的申请与部署流程。无论是个人网站还是企业应用,用户都能根据自身需求,在阿里云找到合适的SSL证书解决方案。
|
4月前
|
弹性计算 运维 安全
从零到一:手把手教你10分钟在阿里云ECS上部署个人博客
本文教你10分钟内用阿里云ECS快速部署个人博客。无需技术基础,只需阿里云账号和公网IP,通过WordPress应用镜像一键搭建。支持域名绑定、HTTPS加密与主题美化,并提供成本优化与安全建议,助你轻松拥有专属技术博客空间。
|
10月前
|
数据采集 人工智能 安全
动态IP代理与静态IP代理的深度解析及国内服务评估
动态IP代理与静态IP代理在技术原理、性能表现及应用场景上各有千秋。动态IP通过IP池轮换实现高频短时访问,适合预算有限的企业,成本低、效率高;静态IP采用固定分配模式,连接稳定且安全性强,适配长期会话需求。国内服务商分三大梯队,提供多样化方案。选型需综合业务需求、安全要求与成本预算,未来技术发展将推动代理服务更高效、可信。企业应根据解析评估,选择适配方案以提升竞争力。
502 0
|
7月前
|
Apache 数据安全/隐私保护 Docker
【开源问答系统】GitHub 14.9k star 的开源问答引擎来了,三分钟搭建完成~~~
Apache Answer 是一款开源问答系统,助力团队将零散知识沉淀为结构化资产。支持 Docker 快速部署、插件扩展、权限控制与多语言,兼具高效搜索、投票排序与私有化部署能力,适用于技术社区、企业知识库与用户支持场景。
910 22
|
8月前
|
小程序 JavaScript API
uni-halo + 微信小程序开发实录:我的第一个作品诞生记
这篇文章介绍了使用uni-halo框架进行微信小程序开发的过程,包括选择该框架的原因、开发目标以及项目配置和部署的步骤。
446 0
uni-halo + 微信小程序开发实录:我的第一个作品诞生记
|
8月前
|
缓存 运维 安全
WordPress安全加速:Cloudflare + Nginx缓存优化方案
本文介绍如何通过Cloudflare与Nginx优化WordPress网站性能,涵盖静态资源长期缓存、动态页面智能缓存及敏感路径保护,提升加载速度并保障后台安全。适用于使用Cloudflare与Nginx环境的WordPress站点。
391 0
|
存储 Java 索引
【数据结构】链表从实现到应用,保姆级攻略
本文详细介绍了链表这一重要数据结构。链表与数组不同,其元素在内存中非连续分布,通过指针连接。Java中链表常用于需动态添加或删除元素的场景。文章首先解释了单向链表的基本概念,包括节点定义及各种操作如插入、删除等的实现方法。随后介绍了双向链表,说明了其拥有前后两个指针的特点,并展示了相关操作的代码实现。最后,对比了ArrayList与LinkedList的不同之处,包括它们底层实现、时间复杂度以及适用场景等方面。
460 10
【数据结构】链表从实现到应用,保姆级攻略
|
缓存 前端开发 JavaScript
前端 JS 经典:构建工具
前端 JS 经典:构建工具
446 0

热门文章

最新文章

下一篇
开通oss服务