admin 管理员组

文章数量: 893695

优化域名转IP地址

点击查看源码

getaddrinfo/gethostbyname等方法会到DNS服务器查询域名与IP地址的映射关系,查询过程中需要发送并接收UDP包进行数据交互,这个过程就会产生延时。实际上域名与IP地址的映射关系不会频繁变动,所有没有必要每次都到DNS服务器上查询域名与IP地址的映射关系,我们可以封装一个域名转IP地址的方法,添加一级本地DNS缓存,从而显著提高程序中域名转IP地址的速度。

实现DNS本地缓存前我们需要一把锁用来保存本地缓存,下面我们实现一个自旋锁类(用C++11原子操作实现)

//自旋锁类
class SpinMutex
{
private:atomic_flag flag = ATOMIC_FLAG_INIT;public:void lock(){while (flag.test_and_set(memory_order_acquire));}void unlock(){flag.clear(std::memory_order_release);}
};

getaddrinfo/gethostbyname等函数的简单包装,提供更简单的接口

//将域名转换成IP地址
const char* GetHostAddress(const char* host, char* ip)
{
#ifndef _MSC_VER    /*LINUX下的实现*/struct addrinfo tmp;struct addrinfo* res;struct sockaddr_in* addr;memset(&tmp, 0, sizeof(tmp));tmp.ai_family = AF_INET;tmp.ai_flags = AI_PASSIVE;tmp.ai_socktype = SOCK_STREAM;if (getaddrinfo(host, NULL, &tmp, &res) < 0) return NULL;addr = (struct sockaddr_in*)(res->ai_addr);ip = (char*)(inet_ntop(AF_INET, &addr->sin_addr, ip, 24));freeaddrinfo(res);
#else                /*WINDOWS下的实现*/struct hostent* entry = gethostbyname(host);if (entry == NULL) return NULL;sprintf(ip, "%d.%d.%d.%d",(entry->h_addr_list[0][0] & 0x00ff),(entry->h_addr_list[0][1] & 0x00ff),(entry->h_addr_list[0][2] & 0x00ff),(entry->h_addr_list[0][3] & 0x00ff));
#endifreturn ip;
}

添加本地DNS缓存,缓存有效时间暂定1分钟

//将域名转换成IP地址
string GetHostAddress(const string& host, bool cache = true)
{static SpinMutex mtx;static map<string, string> hostmap;char buffer[64] = {0};time_t now = time(NULL);const time_t delay = 60;static time_t uptime = 0;//检查缓存是否超时if (uptime + delay > now){std::lock_guard<SpinMutex> lk(mtx);hostmap.clear();uptime = now;}//优先从缓存中查询while (cache){std::lock_guard<SpinMutex> lk(mtx);auto it = hostmap.find(host);if (it == hostmap.end()) break;return it->second;}GetHostAddress(host.c_str(), buffer);//更新缓存if (cache){std::lock_guard<SpinMutex> lk(mtx);hostmap[host] = buffer;}return buffer;
}

欢迎点击查看完整测试代码

本文标签: 优化域名转IP地址