图一 getip1的运行画面
下面是 getip1 程序的代码,很简单:
// getip1.cpp // // 本程序报告本机上每一块网卡的IP地址 // 命令行编译命令为: // // cl getip1.cpp wsock32.lib // // 请一定要在环境变量中正确指定LIB库的路径;可以运行vcvars32.bat // #include <winsock.h> #include <wsipx.h> #include <wsnwlink.h> #include <stdio.h> int main() { // 初始化 Windows sockets API. 要求版本为 version 1.1 // WORD wVersionRequested = MAKEWORD(1, 1); WSADATA wsaData; if (WSAStartup(wVersionRequested, &wsaData)) { printf("WSAStartup failed %s/n", WSAGetLastError()); return -1; } // // 获得主机名. // char hostname[256]; int res = gethostname(hostname, sizeof(hostname)); if (res != 0) { printf("Error: %u/n", WSAGetLastError()); return -1; } printf("hostname=%s/n", hostname); // 根据主机名获取主机信息. // hostent* pHostent = gethostbyname(hostname); if (pHostent==NULL) { printf("Error: %u/n", WSAGetLastError()); return -1; } // // 解析返回的hostent信息. // hostent& he = *pHostent; printf("name=%s/naliases=%s/naddrtype=%d/nlength=%d/n", he.h_name, he.h_aliases, he.h_addrtype, he.h_length); sockaddr_in sa; for (int nAdapter=0; he.h_addr_list[nAdapter]; nAdapter++) { memcpy ( &sa.sin_addr.s_addr, he.h_addr_list[nAdapter],he.h_length); // 输出机器的IP地址. printf("Address: %s/n", inet_ntoa(sa.sin_addr)); // 显示地址串 } // // 终止 Windows sockets API // WSACleanup(); return 0; }要使用Winsock,首先必须调用WSAStartup,最后结束时不要忘了调用WSACleanup。要获取IP地址,首先必须得到机器的主机名(host name),调用gethostname就可以实现,有了主机名,接下来调用gethostbyname来获取包括IP地址在内的更多的主机信息。gethostbyname返回一个指向hostent数据结构的指针,这个结构在<winsock.h>文件中是这样定义的:
// 来自winsock.h struct hostent { char FAR * h_name; /* 正式的主机名*/ char FAR * FAR * h_aliases; /* 别名列表*/ short h_addrtype; /* 主机地址类型*/ short h_length; /* 地址长度*/ char FAR * FAR * h_addr_list; /* 地址清单*/ };
这是个典型的底层APIs使用的数据结构,很多人都不是很熟悉它。实际上,hostent是一个变长的数据结构,h_name是主机名,在例子程序中的值为 "zxn.hangwire.sdb"。没有别名(h_aliases)。h_addrtype是地址类型(或者也叫地址家族),在例子程序中的值为2(AF_INET = internet,其它内容参见winsock.h)。h_length是每一个地址的长度,以字节为单位。因为IP地址的长度是4个字节,所以在例子程序中的值为4,h_addr_list是地址数组的开始点,它们一个接着一个存放,结尾是一个null。每一个x.y.z.w数字占一个字节。为了将IP地址格式化为x.y.z.w的形式,必须将地址数组先拷贝到一个叫sockaddr的数据结构中,然后调用一个特殊的函数inet_ntoa。 图二是hostent 结构在内存中存放示意图:
图二 hostent 结构在内存中的存放示意图
相信以上的解释再辅以阅读代码,你以后不再会对hostent结构感到陌生。
现在.NET风靡一时,用C#语言编程也成为一种时尚,如果有谁想知道如何用C#来解决本文的问题,请参考精华区的相关内容:
“C#编程如何获取某台机器的IP地址?”
最后,顺祝编程愉快!
// 源程序
///
// VCKBASE Online Journal
//
// getip1.cpp
//
// This program reports the IP address for each adapter in your machine.
// To compile from command-line type:
//
// cl getip1.cpp wsock32.lib
//
// Make sure your INCLUDE and LIB environment variables are set up properly;
// you can run vcvars32.bat
//
#include <winsock.h>
#include <wsipx.h>
#include <wsnwlink.h>
#include <stdio.h>
int main()
{
// Initialize windows sockets API. Ask for version 1.1
//
WORD wVersionRequested = MAKEWORD(1, 1);
WSADATA wsaData;
if (WSAStartup(wVersionRequested, &wsaData)) {
printf("WSAStartup failed %s/n", WSAGetLastError());
return -1;
}
//
// Get host name.
//
char hostname[256];
int res = gethostname(hostname, sizeof(hostname));
if (res != 0) {
printf("Error: %u/n", WSAGetLastError());
return -1;
}
printf("hostname=%s/n", hostname);
// Get host info for hostname.
//
hostent* pHostent = gethostbyname(hostname);
if (pHostent==NULL) {
printf("Error: %u/n", WSAGetLastError());
return -1;
}
//
// Parse the hostent information returned
//
hostent& he = *pHostent;
printf("name=%s/naliases=%s/naddrtype=%d/nlength=%d/n",
he.h_name, he.h_aliases, he.h_addrtype, he.h_length);
sockaddr_in sa;
for (int nAdapter=0; he.h_addr_list[nAdapter]; nAdapter++) {
memcpy ( &sa.sin_addr.s_addr, he.h_addr_list[nAdapter],he.h_length);
// Output the machines IP Address.
printf("Address: %s/n", inet_ntoa(sa.sin_addr)); // display as string
}
//
// Terminate windows sockets API
//
WSACleanup();
return 0;
}