[C++]输出本机所有ip地址
int main() { char name[256]; gethostname(name, sizeof(name)); in_addr addr; addrinfo* res; addrinfo hints; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; /* Allow IPv4 */ hints.ai_flags = AI_PASSIVE;/* For wildcard IP address */ hints.ai_protocol = 0; /* Any protocol */ hints.ai_socktype = SOCK_STREAM; getaddrinfo(name,NULL,&hints,&res); while (res != NULL) { struct sockaddr* temp = res->ai_addr; int c; for (int i = 0; i < 3; ++i) { c = (int)(unsigned char)(*temp).sa_data[i + 2]; cout << c << '.'; } c = (int)(unsigned char)(*temp).sa_data[5]; cout << c << endl; res = res->ai_next; } }
gethostname 函数获得了我的电脑的名字 "DESKTOP-GA8048R"
将这个名字与hint输入到getaddrinfo 中去,输出地址信息链表到res指针中
接下来遍历res指针的链表,将地址输出,得到:
192.168.222.1
192.168.146.1
192.168.3.71
注意,192.168.222.1这4位分别储存在char[14]数组sa_data的4个char中,需要先转换为无符号char,再转换为数字int。
上面3个ip地址有一个是真正的网卡地址,另外两个是虚拟机vmware的地址。
上面我们用到的是sockaddr,它的定义如下
typedef struct sockaddr { #if (_WIN32_WINNT < 0x0600) u_short sa_family; #else ADDRESS_FAMILY sa_family; // Address family. #endif //(_WIN32_WINNT < 0x0600) CHAR sa_data[14]; // Up to 14 bytes of direct address. } SOCKADDR, *PSOCKADDR, FAR *LPSOCKADDR;
下面尝试结构sockaddr_in,它的定义如下
typedef struct sockaddr_in { #if(_WIN32_WINNT < 0x0600) short sin_family; #else //(_WIN32_WINNT < 0x0600) ADDRESS_FAMILY sin_family; #endif //(_WIN32_WINNT < 0x0600) USHORT sin_port; IN_ADDR sin_addr; //储存地址的地方 CHAR sin_zero[8]; } SOCKADDR_IN, *PSOCKADDR_IN;
储存地址有3种方式:4个byte,2个word,和一个ulong。
typedef struct in_addr { union { struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { USHORT s_w1,s_w2; } S_un_w; ULONG S_addr; } S_un; #define s_addr S_un.S_addr /* can be used for most tcp & ip code */ #define s_host S_un.S_un_b.s_b2 // host on imp #define s_net S_un.S_un_b.s_b1 // network #define s_imp S_un.S_un_w.s_w2 // imp #define s_impno S_un.S_un_b.s_b4 // imp # #define s_lh S_un.S_un_b.s_b3 // logical host } IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;
观察他们的值:
注意到43200=168*256+192
478=1*256+222
这说明本机使用的是little endian,高位放在后面。
同理31369408=1<<24+222<<16+168<<8+192
代码基本相同,只不过要加上强制类型转换。
int main() { char name[256]; gethostname(name, sizeof(name)); in_addr addr; addrinfo* res; addrinfo hints; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; /* Allow IPv4 */ hints.ai_flags = AI_PASSIVE;/* For wildcard IP address */ hints.ai_protocol = 0; /* Any protocol */ hints.ai_socktype = SOCK_STREAM; getaddrinfo(name,NULL,&hints,&res); while (res != NULL) { struct sockaddr_in* temp = (sockaddr_in*)res->ai_addr; int c; c = (int)(*temp).sin_addr.S_un.S_un_b.s_b1; cout << c << '.'; c = (int)(*temp).sin_addr.S_un.S_un_b.s_b2; cout << c << '.'; c = (int)(*temp).sin_addr.S_un.S_un_b.s_b3; cout << c << '.'; c = (int)(*temp).sin_addr.S_un.S_un_b.s_b4; cout << c <<endl; res = res->ai_next; } }
hints指示了我们想要收到什么样的地址。假如删掉hints,输入参数由&hints转变为NULL,那么输出为:
0.0.0.0
0.0.0.0
0.0.0.0
192.168.222.1
192.168.146.1
192.168.3.71
在局部变量窗口中发现,前3个0.0.0.0对应的 sin_family为23,也就是ipv6,而后面三个地址对应的 sin_family为2,也就是ipv4
由于之前hint限定了ipv4,所以删掉后出现了ipv6的地址。但至于为什么是0.0.0.0,我也不知道,因为我没有开过ipv6。
hints.ai_family = AF_INET; /* Allow IPv4 */