本文是读者朋友的面试真题,客户端如何获取本地的公网IP。
在当今的网络时代,许多程序和服务都依赖于公网IP——用于标识设备在互联网位置的全球唯一标识符。例如,Web服务器、FTP服务器或游戏服务器等需要借助公网IP来确保用户可以访问。故此准确获取公网IP地址显得尤为重要。
日常接触到的形如192.168.1.100等IP地址,都是私网IP,它们只在局域网内有效,不能在互联网上被识别。而公网IP(Public IP Address)是由互联网服务提供商(ISP)分配给用户的地址,它用于在全球互联网上标识一个设备。公网IP与私网IP之间通过NAT(网络地址转换)实现转换,使得多台设备可以共享一个公网IP。
公网IP有着至关重要的作用:
可是该如何获取公网地址呢?
为了方便用户查询公网IP,许多网站提供了公网IP查询服务。这些网站通常提供一个简单的接口,用户只需访问这些网站,即可获取到自己的公网IP。常见的IP查询服务网址如下:
http://api.ipify.org
http://icanhazip.com
http://checkip.amazonaws.com
http://ipinfo.io/ip
http://myexternalip.com/raw
http://www.trackip.net/ip
http://ipecho.net/plain
http://myip.dnsomatic.com
http://www.ip-adress.com/
在浏览器内请求如上的任意一个网址,即可获取公网IP地址。
虽然如上的IP查询服务网站可以方便地获取到公网IP,但开发者终究还是需要落实到代码上,代码实现时依然可以借助如上的IP查询服务网站,实现的思路如下:
在实现网络请求时,借助C++的libcurl
库,可通过vcpkg工具下载该库,vcpkg的使用见之前的文章——vcpkg 如何改变开发流程? ;libcurl的使用见之前的文章——无论多么复杂的网络请求,只需要这7步就够了 。
以下是一个C++类的实现,它会依次尝试多个公共API来获取本机的公网IP。如果第一个API请求失败,它会继续尝试下一个,直到找到一个有效的IP或者所有都失请求都失败为止。
#include <iostream>
#include <string>
#include <curl/curl.h>
#include <vector>
class PublicIPFetcher {
public:
// 构造函数初始化API列表
PublicIPFetcher() {
// 这里列出了10个公网IP查询API(可根据需要增加/修改)
apis = {
"http://api.ipify.org";
"http://icanhazip.com";
"http://checkip.amazonaws.com";
"http://ipinfo.io/ip";
"http://myexternalip.com/raw";
"http://www.trackip.net/ip";
"http://ipecho.net/plain";
"http://myip.dnsomatic.com";
"http://www.ip-adress.com/";
};
}
// 获取公网IP,按顺序依次请求API
bool getPublicIP(std::string& ip) {
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (!curl) {
std::cerr << "Curl initialization failed!" << std::endl;
curl_global_cleanup();
returnfalse;
}
for (constauto& api : apis) {
ip.clear(); // 清空之前的IP
curl_easy_setopt(curl, CURLOPT_URL, api.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ip);
res = curl_easy_perform(curl);
if (res == CURLE_OK && !ip.empty()) {
std::cout << "Public IP fetched from: " << api << std::endl;
curl_easy_cleanup(curl);
curl_global_cleanup();
returntrue;
}
}
// 如果所有API都失败
curl_easy_cleanup(curl);
curl_global_cleanup();
returnfalse;
}
private:
// 保存API列表
std::vector<std::string> apis;
// 写入回调函数,将获取的数据保存到ip变量中
static size_t writeCallback(void* contents, size_t size, size_t nmemb, void* userp) {
size_t totalSize = size * nmemb;
((std::string*)userp)->append((char*)contents, totalSize);
return totalSize;
}
};
int main() {
PublicIPFetcher fetcher;
std::string ip;
if (fetcher.getPublicIP(ip)) {
std::cout << "Public IP: " << ip << std::endl;
} else {
std::cout << "Failed to retrieve public IP." << std::endl;
}
return0;
}
如上的代码,getPublicIP函数返回false,说明没有成功获取公网IP;返回true,则说明成功获取了公网IP,并且IP地址会保存在ip变量中。
通过C++代码获取公网IP的需求在许多网络应用中是常见的,尤其是在需要与外部网络进行交互时。通过向多个IP查询服务网站发送请求,可以提高获取公网IP的可靠性。本文提供了一个可以动态尝试多个API的C++类来实现这一功能。