我目前正在寻找一种便携式的方法来获取本地IP地址。因为我正在使用Boost,所以我认为使用Boost.Asio来完成这个任务是个不错的主意。
网络上有几个例子,应该可以完成这个任务。例子。
我尝试了两个代码,只是稍作修改。Boost.Doc上的代码被修改为不解析 "www.boost.org",而是解析 "localhost "或我的主机名。为了得到主机名,我使用了 boost::asio::ip::host_name(),或者直接输入一个字符串。
此外,我还写了我自己的代码,它融合了上面的例子和我从Boost文档和其他例子中收集到的(少量)知识。
所有的源码都能正常工作,但它们只是返回了以下IP:127.0.1.1(这不是打字错误,最后是0.1.1)我在Ubuntu 9.10和GCC 4.4.1上运行并编译了这段代码。
一个同事在他的机器上尝试了同样的代码,得到的是127.0.0.2(也不是打字错误......)他在Suse 11.0和GCC 4.4.1上编译并运行了代码(我不是100%的肯定
我不知道是否可以改变本地主机(127.0.0.1),但我知道我和我的同事都没有这样做。ifconfig说loopback使用127.0.0.1。ifconfig也找到了我正在搜索的公共IP(在我的例子中是141.200.182.30,子网是255.255.0.0
所以这是否是 Linux 的问题,而且代码不像我想象的那样可移植?我是否需要改变一些其他的东西,或者Boost.Asio根本不能解决我的问题?
我知道在Stackoverflow和其他网页上有很多关于类似主题的问题,但我找不到对我的情况有用的信息。如果你有有用的链接,如果你能给我指出来,那就太好了。
PS:这是我从Boost.Doc上修改的代码。
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(boost::asio::ip::host_name(), "");
tcp::resolver::iterator iter = resolver.resolve(query);
tcp::resolver::iterator end; // End marker.
while (iter != end)
{
tcp::endpoint ep = *iter++;
std::cout << ep << std::endl;
}
这是我从python网络编程(google)中学到的一招,用来计算我的机器的ip地址。这只有在你有互联网连接并能连接到google.com的情况下才有效,而且确实给了我家里机器的192.168.x.x私人地址。
try {
boost::asio::io_service netService;
udp::resolver resolver(netService);
udp::resolver::query query(udp::v4(), "google.com", "");
udp::resolver::iterator endpoints = resolver.resolve(query);
udp::endpoint ep = *endpoints;
udp::socket socket(netService);
socket.connect(ep);
boost::asio::ip::address addr = socket.local_endpoint().address();
std::cout << "My IP according to google is: " << addr.to_string() << std::endl;
} catch (std::exception& e){
std::cerr << "Could not deal with socket. Exception: " << e.what() << std::endl;
}
你可以找到 "你 "的地址,你发布的代码。 但是......它变得复杂。 可能有多个网卡,可能有局域网和广域网地址,有线和无线,环回...... 在我的桌面上,我有一个NIC,但两个ips这里从两个不同的DHCP服务器在我的LAN... ...
我发现最好让用户提供IP作为命令行参数来绑定。 是的,这是一个便携的解决方案! :-)
如果你编辑你的etchosts文件(这只是*nix的,也可能适用于windows...我不确定),你可以纠正这个问题。
在hosts文件中,你会发现这样的内容。(这是Ubuntu,注意1.1)
127.0.0.1 localhost 127.0.1.1 yourPcName.yourNetwork.tld
如果你把这个文件改成
127.0.0.1 localhost 127.0.1.1 yourPcName.yourNetwork.tld your.real.ip.here yourPcName.
那么主机名就应该正确解析。
一个测试正确解析的方法是用 "hostname -i "命令,它应该在你更换主机之前打印出你的ip地址不正确,之后再正确打印。
当然这对于动态IP来说是很糟糕的解决方案......诶。
跨平台,但只是因为 #ifdef _WIN32 … #else
:
boost::asio::ip::address_v6 sinaddr_to_asio(sockaddr_in6 *addr) {
boost::asio::ip::address_v6::bytes_type buf;
memcpy(buf.data(), addr->sin6_addr.s6_addr, sizeof(addr->sin6_addr));
return boost::asio::ip::make_address_v6(buf, addr->sin6_scope_id);
}
#if defined(_WIN32)
#undef UNICODE
#include <winsock2.h>
// Headers that need to be included after winsock2.h:
#include <iphlpapi.h>
#include <ws2ipdef.h>
typedef IP_ADAPTER_UNICAST_ADDRESS_LH Addr;
typedef IP_ADAPTER_ADDRESSES *AddrList;
std::vector<boost::asio::ip::address> get_local_interfaces() {
// It's a windows machine, we assume it has 512KB free memory
DWORD outBufLen = 1 << 19;
AddrList ifaddrs = (AddrList) new char[outBufLen];
std::vector<boost::asio::ip::address> res;
ULONG err = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, ifaddrs,
&outBufLen);
if (err == NO_ERROR) {
for (AddrList addr = ifaddrs; addr != 0; addr = addr->Next) {
if (addr->OperStatus != IfOperStatusUp) continue;
// if (addr->NoMulticast) continue;
// Find the first IPv4 address
if (addr->Ipv4Enabled) {
for (Addr *uaddr = addr->FirstUnicastAddress; uaddr != 0; uaddr = uaddr->Next) {
if (uaddr->Address.lpSockaddr->sa_family != AF_INET) continue;
res.push_back(boost::asio::ip::make_address_v4(ntohl(reinterpret_cast<sockaddr_in *>(addr->ifa_addr)->sin_addr.s_addr)));
}
}
if (addr->Ipv6Enabled) {
for (Addr *uaddr = addr->FirstUnicastAddress; uaddr != 0; uaddr = uaddr->Next) {
if (uaddr->Address.lpSockaddr->sa_family != AF_INET6) continue;
res.push_back(sinaddr_to_asio(reinterpret_cast<sockaddr_in6 *>(addr->ifa_addr)));
}
}
}
} else {
}
delete[]((char *)ifaddrs);
return res;
}
#elif defined(__APPLE__) || defined(__linux__)
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <sys/types.h>
std::vector<boost::asio::ip::address> get_local_interfaces() {
std::vector<boost::asio::ip::address> res;
ifaddrs *ifs;
if (getifaddrs(&ifs)) {
return res;
}
for (auto addr = ifs; addr != nullptr; addr = addr->ifa_next) {
// No address? Skip.
if (addr->ifa_addr == nullptr) continue;
// Interface isn't active? Skip.
if (!(addr->ifa_flags & IFF_UP)) continue;
if(addr->ifa_addr->sa_family == AF_INET) {
res.push_back(boost::asio::ip::make_address_v4(ntohl(
reinterpret_cast<sockaddr_in *>(addr->ifa_addr)->sin_addr.s_addr)));
} else if(addr->ifa_addr->sa_family == AF_INET6) {
res.push_back(sinaddr_to_asio(reinterpret_cast<sockaddr_in6 *>(addr->ifa_addr)));
} else continue;
}
freeifaddrs(ifs);
return res;
}
#else
#error "..."
#endif