多網絡卡情況下如何正確獲得IP
這幾天在自己的個人機器上裝了個虛擬機器VMWare。然後在程式中獲得本地IP,發現,是錯誤的,發現獲得的IP竟然不是原來的192.168.1.155,而是一個奇怪的192.168.233.1。後來發現,原來自己裝了虛擬機器,這個地址是自己虛擬機器VMWare VMNet8的地址,而且,這個網路被命名為本地連線2。
看下我自己原來的程式碼,是用的gethostbyname方法獲得的。於是,寫了個Demo程式,進行執行
#include<WinSock2.h> #include<windef.h> #include<ws2tcpip.h> #include<stdio.h> int main(int argc, char *argv[]) { char *ptr, **pptr; struct hostent *hptr; struct hostent *pHPtr; char str[32]; WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD( 2, 0 ); char name[100]; ptr = name; if (0 == WSAStartup( wVersionRequested, &wsaData ) ) { if(0 != gethostname ( ptr, strlen(ptr)) ) { printf("沒有獲得名稱\n"); return -1; } if (NULL == (hptr = gethostbyname(ptr))) { printf("獲得地址錯誤\n"); return -1; } printf("機器的正式名字是: %s\n", ptr); for (pptr = hptr->h_aliases; *pptr != NULL; pptr++) { printf("別名是: %s\n", *pptr); } int i = 1; switch(hptr->h_addrtype) { case AF_INET: case AF_INET6: pptr = hptr->h_addr_list; for(; *pptr != NULL; pptr++) { printf("地址是: %s\n", inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str))); } pHPtr = hptr; for (pptr = hptr->h_addr_list; *pptr != NULL; pptr++) { //inet_ntop的實質 printf("第%d 個地址是: %d.%d.%d.%d\n", i, pHPtr->h_addr_list[i-1][0] & 0x00ff, pHPtr->h_addr_list[i-1][1] & 0x00ff, pHPtr->h_addr_list[i-1][2] & 0x00ff, pHPtr->h_addr_list[i-1][3]& 0x00ff); printf("第%d 個地址是: %s\n", i++, inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)) ); } printf("第一個地址是: %s\n", inet_ntop(hptr->h_addrtype, hptr->h_addr, str, sizeof(str))); break; default: printf("未知地址型別\n"); } WSACleanup( ); } return 0; }
執行結果如圖所示:
原來,第一個地址早已不是我自己的本地地址,而是VMNet8 的地址。
我查下相應函式的用法,相應資訊如下:
struct hostent *gethostbyname(const char *name);
這個函式的傳入值是域名或者主機名,例如"www.google.cn"等等。傳出值,是一個hostent的結構。如果函式呼叫失敗,將返回NULL。
返回hostent結構體型別指標
struct hostent
{
char *h_name;
char **h_aliases;
int h_addrtype;
int h_length;
char **h_addr_list;
#define h_addr h_addr_list[0]
};
hostent->h_name
表示的是主機的規範名。例如www.google.com的規範名其實是www.l.google.com。
hostent->h_aliases
表示的是主機的別名.www.google.com就是google他自己的別名。有的時候,有的主機可能有好幾個別名,這些,其實都是為了易於使用者記憶而為自己的網站多取的名字。
hostent->h_addrtype
表示的是主機ip地址的型別,到底是ipv4(AF_INET),還是pv6(AF_INET6)
hostent->h_length
表示的是主機ip地址的長度
——————————————以上是分割線————————————————————————————
可見,通過gethostbyname 的方法獲取IP的方法也是可以的,只是這個VMNet 8地址確實排在前面,我無法修改。
而且gethostbyname是遞迴通過DNS阻塞查詢主機名和IP,很影響效率。據說好多公司做爬蟲都是自己查詢主機名和網站名的IP,不用gethostbyname,就是因為gethostbyname效率太低了。
繼續查資料。
發現一個函式GetAdaptersInfo,getAdapterInfo相應參考資料如下:
GetAdaptersInfo函式:
DWORD GetAdaptersInfo(// 接受資料的緩衝區,指向一個結構IP_ADAPTER_INFO
PIP_ADAPTER_INFO pAdapterInfo,
// 指向輸出緩衝區的大小的指標
PULONG pOutBufLen
);
這個函式中最重要是第一個引數,看看這個結構有點啥?MSDN中說明如下:
typedef struct _IP_ADAPTER_INFO {struct _IP_ADAPTER_INFO* Next; // 連結串列指標,指向下一個單元
DWORD ComboIndex;
char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4]; // 介面資訊物理名稱
char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];// 介面描述資訊
UINT AddressLength; // MAC地址的長度
BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH]; // MAC地址
DWORD Index;
UINT Type;
UINT DhcpEnabled;
PIP_ADDR_STRING CurrentIpAddress;
IP_ADDR_STRING IpAddressList; // IP地址列表
IP_ADDR_STRING GatewayList; // 閘道器地址列表
IP_ADDR_STRING DhcpServer; // DHCP地址
BOOL HaveWins;
IP_ADDR_STRING PrimaryWinsServer; // 首選WINS 伺服器
IP_ADDR_STRING SecondaryWinsServer; // 備用WINS伺服器
time_t LeaseObtained;
time_t LeaseExpires;
} IP_ADAPTER_INFO, *PIP_ADAPTER_INFO; ————————————————————以上是分割線———————————————————— 於是,參照相應樣例,寫出如下程式碼:
#include<winsock.h>
#include<stdio.h>
#include<IPHlpApi.h>
#pragma comment(lib, "IPHlpApi.Lib")
int main()
{
IP_ADAPTER_INFO IOInfo[20];
PIP_ADAPTER_INFO pIOInfo = NULL;
DWORD Result = 0;
unsigned long nLen = sizeof(IOInfo);
Result = GetAdaptersInfo(IOInfo, &nLen);
if (NO_ERROR != Result)
{
fprintf(stderr, "GetAdaptersInfo Error!\n");
return -1;
}
else
{
pIOInfo = IOInfo;
int Num = 0;
while (pIOInfo != NULL)
{
fprintf(stdout, "\n--------------------Num.%d-------------------------\n", Num);
printf("|Name:%s\n", pIOInfo->AdapterName);
printf("|Desc:%s\n", pIOInfo->Description);
printf("|IP:%s\n", pIOInfo->IpAddressList.IpAddress.String);
printf("|MAC:%02X:%02X:%02X:%02X:%02X:%02X\n", pIOInfo->Address[0], pIOInfo->Address[1], pIOInfo->Address[2],
pIOInfo->Address[3], pIOInfo->Address[4], pIOInfo->Address[5]);
printf("|GateWay:%s\n", pIOInfo->GatewayList.IpAddress.String);
printf("--------------------Num.%d-------------------------", Num++);
pIOInfo = pIOInfo->Next;
}
}
return 0;
}
執行結果如下:
我看到,執行程式確實區分出了VM的網絡卡和本地網絡卡;無奈本地網絡卡很有可能變,而本地網絡卡的Desc不足以填充足夠的資訊,從而為作為整個資訊的區分。 我突然想到IPConfig命令,可以完全顯示出網絡卡和網路的名稱,於是,收啟發,想進行IPConfig命令,然後獲取資訊,再獲得IP地址。 在我的機器上執行ipconfig /all 命令,獲得結果如下:
Windows IP 配置
主機名 . . . . . . . . . . . . . : USER-20151221DQ
主 DNS 字尾 . . . . . . . . . . . :
節點型別 . . . . . . . . . . . . : 混合
IP 路由已啟用 . . . . . . . . . . : 否
WINS 代理已啟用 . . . . . . . . . : 否
乙太網介面卡 本地連線 2:
連線特定的 DNS 字尾 . . . . . . . : localdomain
描述. . . . . . . . . . . . . . . : VMware Virtual Ethernet Adapter for VMnet8
實體地址. . . . . . . . . . . . . : 00-50-56-C0-00-08
DHCP 已啟用 . . . . . . . . . . . : 是
自動配置已啟用. . . . . . . . . . : 是
本地連結 IPv6 地址. . . . . . . . : fe80::643d:e61d:7f3:fb4d%15(首選)
IPv4 地址 . . . . . . . . . . . . : 192.168.233.1(首選)
子網掩碼 . . . . . . . . . . . . : 255.255.255.0
獲得租約的時間 . . . . . . . . . : 2016年7月19日 9:26:32
租約過期的時間 . . . . . . . . . : 2016年7月19日 13:41:32
預設閘道器. . . . . . . . . . . . . :
DHCP 伺服器 . . . . . . . . . . . : 192.168.233.254
DHCPv6 IAID . . . . . . . . . . . : 318787670
DHCPv6 客戶端 DUID . . . . . . . : 00-01-00-01-1E-09-9D-1C-2C-41-38-8E-9C-F8
DNS 伺服器 . . . . . . . . . . . : 192.168.233.2
主 WINS 伺服器 . . . . . . . . . : 192.168.233.2
TCPIP 上的 NetBIOS . . . . . . . : 已啟用
乙太網介面卡 VMware Network Adapter VMnet1:
連線特定的 DNS 字尾 . . . . . . . :
描述. . . . . . . . . . . . . . . : VMware Virtual Ethernet Adapter for VMnet1
實體地址. . . . . . . . . . . . . : 00-50-56-C0-00-01
DHCP 已啟用 . . . . . . . . . . . : 否
自動配置已啟用. . . . . . . . . . : 是
本地連結 IPv6 地址. . . . . . . . : fe80::acef:74f3:abe2:7f54%13(首選)
IPv4 地址 . . . . . . . . . . . . : 192.168.254.1(首選)
子網掩碼 . . . . . . . . . . . . : 255.255.255.0
預設閘道器. . . . . . . . . . . . . :
DHCPv6 IAID . . . . . . . . . . . : 302010454
DHCPv6 客戶端 DUID . . . . . . . : 00-01-00-01-1E-09-9D-1C-2C-41-38-8E-9C-F8
DNS 伺服器 . . . . . . . . . . . : fec0:0:0:ffff::1%1
fec0:0:0:ffff::2%1
fec0:0:0:ffff::3%1
TCPIP 上的 NetBIOS . . . . . . . : 已啟用
乙太網介面卡 本地連線:
連線特定的 DNS 字尾 . . . . . . . :
描述. . . . . . . . . . . . . . . : Intel(R) 82579LM Gigabit Network Connection
實體地址. . . . . . . . . . . . . : 2C-41-38-8E-9C-F8
DHCP 已啟用 . . . . . . . . . . . : 否
自動配置已啟用. . . . . . . . . . : 是
本地連結 IPv6 地址. . . . . . . . : fe80::6822:7d71:8cda:2843%11(首選)
IPv4 地址 . . . . . . . . . . . . : 192.168.1.155(首選)
子網掩碼 . . . . . . . . . . . . : 255.255.255.0
預設閘道器. . . . . . . . . . . . . : 192.168.1.1
DHCPv6 IAID . . . . . . . . . . . : 237781304
DHCPv6 客戶端 DUID . . . . . . . : 00-01-00-01-1E-09-9D-1C-2C-41-38-8E-9C-F8
DNS 伺服器 . . . . . . . . . . . : fec0:0:0:ffff::1%1
fec0:0:0:ffff::2%1
fec0:0:0:ffff::3%1
TCPIP 上的 NetBIOS . . . . . . . : 已啟用
隧道介面卡 isatap.{A5D17715-BE7B-4932-9B76-1F96CFE71258}:
媒體狀態 . . . . . . . . . . . . : 媒體已斷開
連線特定的 DNS 字尾 . . . . . . . :
描述. . . . . . . . . . . . . . . : Microsoft ISATAP Adapter
實體地址. . . . . . . . . . . . . : 00-00-00-00-00-00-00-E0
DHCP 已啟用 . . . . . . . . . . . : 否
自動配置已啟用. . . . . . . . . . : 是
隧道介面卡 isatap.{EFE41274-D6A2-40A2-B625-131EA423FCD6}:
媒體狀態 . . . . . . . . . . . . : 媒體已斷開
連線特定的 DNS 字尾 . . . . . . . :
描述. . . . . . . . . . . . . . . : Microsoft ISATAP Adapter #2
實體地址. . . . . . . . . . . . . : 00-00-00-00-00-00-00-E0
DHCP 已啟用 . . . . . . . . . . . : 否
自動配置已啟用. . . . . . . . . . : 是
隧道介面卡 isatap.localdomain:
媒體狀態 . . . . . . . . . . . . : 媒體已斷開
連線特定的 DNS 字尾 . . . . . . . : localdomain
描述. . . . . . . . . . . . . . . : Microsoft ISATAP Adapter #3
實體地址. . . . . . . . . . . . . : 00-00-00-00-00-00-00-E0
DHCP 已啟用 . . . . . . . . . . . : 否
自動配置已啟用. . . . . . . . . . : 是
-E0
DHCP 已啟用 . . . . .
通過這個,我可以清楚的看到,我的首個IP確實是命名為本地連線2 的 IP,而不是我的本地IP;但是這個上面的網路名稱絕對不錯,“本地連線”這個網路IP是:192.168.1.155
於是,用著執行這個ipconfig的方法的程式,發現,知道一個system函式。發現此函式可以執行命令,但是,顯示不出來命令的回顯。目前也找不到更好的方法
,於是,我想到的方法是,把命令回視訊記憶體到相應檔案裡,然後,再進行讀取後獲得IP。
查詢到一個函式GetCurrentDirectory,然後確保執行的程式建立的檔案在相應的程式的路徑下,可以進行靈活寫入。
整個程式如下:
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<Windows.h>
//#include<WinBase.h>
#ifndef MAXTHPATH
#define MAXTHPATH (256)
#endif
#ifndef IPNUM
#define IPNUM (20)
#endif
#ifndef FILENAME
#define FILENAME ("/NetMask.txt")
#endif
char *getLocalIP(char *pszIP);
int main(int argc, char *argv[])
{
char pszIP[IPNUM] = {0};
getLocalIP(pszIP);
printf("本地IP為 %s\n", pszIP);
//delete []buf;
return 0;
}
char *getLocalIP(char *pszIP)
{
char pPath[MAXTHPATH];
GetCurrentDirectory(MAXTHPATH, pPath);
strcat(pPath, FILENAME);
char pszCmd[MAXTHPATH] = {0};
strcpy(pszCmd, "ipconfig /all > ");
strcpy(pszCmd + strlen(pszCmd), pPath);
//執行DOS命令,並把網路資訊輸出到資料夾下
system(pszCmd);
FILE *fp = fopen(pPath, "r");
fseek(fp, 0, SEEK_END);
int len = ftell(fp);
rewind(fp);
char *pBuf = new char[len+1];
memset(pBuf, 0, len +1);
fread(pBuf, 1, len, fp);
fclose(fp);
//根據一個機器獲得,如果DOS命令變更,可能會發生更改
char *pLAN = strstr(pBuf, "本地連線:");
char *pIPV4 = strstr(pLAN, "IPv4 地址");
pIPV4 = strstr(pIPV4, ":");
pIPV4 += 2; //翻過“:”符號,獲得真正的IP
char *pEnd = strstr(pIPV4, "(");
strncpy(pszIP, pIPV4, pEnd - pIPV4);
//避免記憶體洩露
delete []pBuf;
return pszIP;
}
執行結果如下:
顯然,得到了正確的IP。 幾個值得注意的事情是: 1)在Linux下,此命令應該改為ifconfig; 2)其他機器不知道相應的回顯字串格式是否正確,還有,機器的語言由中文換成英文後,是否能有正確的支援; 3)system函式無法把回顯直接輸出到程式裡; 4)最後獲得IP的過程,讀取字串可以用正則;正則匹配通用性更好,但在windows下不支援正則,要想進行支援,需要新增boost庫進行支援 5)有沒有更好的直接獲取本地IP的方法,雖然此種方法可以獲得多網絡卡,尤其是實際的物理多網絡卡的IP地址
相關推薦
多網絡卡情況下如何正確獲得IP
這幾天在自己的個人機器上裝了個虛擬機器VMWare。然後在程式中獲得本地IP,發現,是錯誤的,發現獲得的IP竟然不是原來的192.168.1.155,而是一個奇怪的192.168.233.1。後來發現,原來自己裝了虛擬機器,這個地址是自己虛擬機器VMWare VM
雙網絡卡或多網絡卡情況下獲得所有的IP地址
在編寫基於sock的網路程式時,有時需列舉系統中繫結的所有IP地址,在一般控制元件無法解決些問題的情況下,可使用如下方法一試:一、基於winsock的方法,例程如下(修改自網上一個名為“GetIP”的程式原始碼):// GetIP.cpp : Defines the entr
Eureka的自我保護模式、多網絡卡環境下的IP選擇和健康檢查
Eureka的自我保護模式 禁用自我保護模式: eureka.server.enable-self-preservation = false 多網絡卡環境下的IP選擇 對於多網絡卡的伺服器,各個微服務註冊到Eureka Server上的IP要如何指定呢? 指定IP在某些場合下
Spring Cloud 多網絡卡環境下Eureka服務註冊IP選擇問題
問題場景 伺服器上分別配置了eth0, eth1和eth2三塊網絡卡,只有eth1的地址可供其它機器訪問,eth0和eth2的 IP 無效。在這種情況下,服務註冊時Eureka Client會自動選擇eth0作為服務ip, 導致其它服務無法呼叫由於官方並沒有寫明Eureka
解決多網絡卡環境下使用特定網絡卡廣播UDP訊息的問題
多網絡卡環境下發送UDP廣播到特定網路通常有以下幾種方式: 將socket繫結到特定網絡卡ip; 使用socket選項; 遍歷網絡卡; 設定路由表。 繫結到特定IP 建立socket後將其繫結到特定IP地址,則傳送廣播詳細的時候會通過此網絡卡傳送。如果我們的
雙網絡卡情況下通過路由表規則指定網絡卡訪問特定ip
今天,同事阿峰外出駐點,而我在公司辦公,他想像以往一樣用teamviewer控制我的電腦去除錯公司的伺服器,我說沒問題。 然而,
Linux下多網絡卡不同IP在同一網段的情況
關鍵字:Strict Interface ARP, Multi-link, Multipath, Multiple network cards on same subnet problem 公司那個提供音樂下載的域名流量直逼1Gbps,但是系統的連線卻不高,伺服器用的是DELL2850的,板載兩個Gbe的
多網絡卡存在情況下獲取指定網絡卡的MAC地址
應用軟體中經常有需要顯示mac地址的功能,方便使用者判斷當前聯網狀態,如果是在多網絡卡存在(無線,有線等)下,網路會經常切換,獲取到的MAC地址可能與預期不同,現給出指定網絡卡獲取mac地址的方法。 void get_mac(Mac_Address &am
CentOS下多網絡卡繫結bond/多網絡卡聚合
網絡卡bond我直接理解成網絡卡聚合了,就是把多張網絡卡虛擬成1張網絡卡,出口時,這張網絡卡無論哪個斷線都不影響網路,入口時,需要結合交換機的埠聚合功能實現和網絡卡配置的bond模式進行負載均衡。bond需要在核心Kernels 2.4.12及以上才能使用,因為需要使用bonding模組。 bond模式:
Eureka客戶端註冊多網絡卡下IP選擇問題
.title { background: #5EA2A2; color: #FFFFFF; font-family: "微軟雅黑", "宋體", "黑體", Arial; font-size: 17px; font-weight: bold; height: 25px; line-height: 25px;
Centos7下多網絡卡的路由轉發配置
Centos7前的版本用iptable 防火牆設定路由轉發 ;Centos7 以後的版本不能使用iptable 防火牆來設定路由器轉發,而是得用firewall-cmd 來設定 首先輸入firewall-cmd --list-all 來檢視當前防火牆配置 假設介面 inte
linux下多網絡卡路由設定
在linux多網絡卡情況下,如不能正確設定路由將導致部分網路不通。 一、檢視路由 使用命令: route 二、預設路由設定 1、刪除預設路由 route del default 2、增加預設路由 route add default gw IP(如:192.168.1.1)
【shell】海思3536 多網絡卡繫結聚合——bond技術
0.原理說明 目前網絡卡繫結mode共有七種(0~6)bond0、bond1、bond2、bond3、bond4、bond5、bond6 常用的有三種: mode=0:平衡負載模式,有自動備援,但需要”Switch”支援及設定。 mode=1:自動備援模式,其中一條線若斷線,其他線路
spring cloud EurekaClient 多網絡卡 ip 配置 和 原始碼分析
1、前言 對於spring cloud,各個服務例項需要註冊到Eureka註冊中心。 一般會配置ip註冊,即eureka.instance.prefer-ip-address=true。 但是,如果服務例項所在的環境存在多個網絡卡,經常會出現註冊過去的ip不是我們想要的ip。
c# 多網絡卡 由【網路介面卡名】獲取網絡卡資訊,IP
c# 多網絡卡 由【網路介面卡名】獲取網絡卡資訊,IP 多網絡卡電腦中,網路介面卡的名字 多樣化! 專案中需要,根據網路介面卡 名字 獲取 單個網絡卡的IP: using System.Net.NetworkInformation;
Linux中高階網路配置-team方式多網絡卡繫結
team簡介 在redhat7.0以上版本,配置多網絡卡繫結時,專門提供了team工具來實現多網絡卡的繫結。 team :也是鏈路聚合 最多支援8塊網絡卡,不需要手動載入相應核心模組 支援模式: broadcast 廣播容錯 roundrobin 輪詢
多網絡卡Ubuntu伺服器安裝Kubernetes
多網絡卡伺服器安裝Kubernetes如何指定叢集選用的IP地址呢? 指定--apiserver-advertise-address引數即可。如下: sudo kubeadm init --kubernetes-version=v1.12.2 --apiserver-advertise-ad
Ubuntu 18.04 設定多網絡卡多埠聚合
多網絡卡聚合把多個網路埠繫結到一個IP地址,可以提高網路總頻寬和容錯能力。 Ubuntu 18.04使用了netplan來管理網路,跟以前版本差別很大。以前版本修改/etc/network/interfaces的方法不再管用,設定多網絡卡聚合的方式也有點不一樣了,不過實際用起來比以前還
雲伺服器多網絡卡配置實踐
環境概述: 系統環境:標準型S2、1核2G、1Mbps、Centos7.4 64位、騰訊雲、北京一區、VPC(私有網路) 遠端連線工具:xshell5 目標: 為伺服器配置 2個網絡卡,每個網絡卡配置2個內網ip、2個外網ip,共計4個外網ip、4
02 Linux 多網絡卡繫結
Linux 多網絡卡繫結 網絡卡繫結mode共有七種(0~6) bond0、bond1、bond2、bond3、bond4、bond5、bond6 常用的有三種 mode=0:平衡負載模式,有自動備援,但需要”Switch”支援及設定。 mode=1:自