方法:C语言获取网卡方法之WSAIoctl函数
在WinSock中可以通过调用WSAIoctl()函数,通过设置标志为SIO_GET_INTERFACE_LIST 的方法获取网络接口信息。其函数在MSDN定义如下:
int WSAIoctl(
SOCKET s, // SOCKET句柄
DWORD dwIoControlCode, // 控制代码,SIO_GET_INTERFACE_LIST在MSDN中并没有是通过宏定义计算转换的
LPVOID lpvInBuffer, // 输入缓冲区的地址
DWORD cbInBuffer,// 出入缓冲区的大小
LPVOID lpvOutBuffer,// 输出缓冲区地址
DWORD cbOutBuffer,// 输出缓冲区大小
LPDWORD lpcbBytesReturned,// 实际输出字节数地址
LPWSAOVERLAPPED lpOverlapped,// WSAOVERLAPPED结构的地址
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine // 操作结束后调用的历程指针
);
SOCKET s, // SOCKET句柄
DWORD dwIoControlCode, // 控制代码,SIO_GET_INTERFACE_LIST在MSDN中并没有是通过宏定义计算转换的
LPVOID lpvInBuffer, // 输入缓冲区的地址
DWORD cbInBuffer,// 出入缓冲区的大小
LPVOID lpvOutBuffer,// 输出缓冲区地址
DWORD cbOutBuffer,// 输出缓冲区大小
LPDWORD lpcbBytesReturned,// 实际输出字节数地址
LPWSAOVERLAPPED lpOverlapped,// WSAOVERLAPPED结构的地址
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine // 操作结束后调用的历程指针
);
该函数定义在ws2tcpip.h中所以要先包含该头文件,另外需要提到的就是存储信息结构体,如下:
typedef struct _INTERFACE_INFO
{
u_long iiFlags;// 接口的类型和状态
struct sockaddr iiAddress;// 接口IP地址
struct sockaddr iiBroadcastAddress; // 接口对应的广播地址
struct sockaddr iiNetmask; // 接口对应的子网掩码
} INTERFACE_INFO;
{
u_long iiFlags;// 接口的类型和状态
struct sockaddr iiAddress;// 接口IP地址
struct sockaddr iiBroadcastAddress; // 接口对应的广播地址
struct sockaddr iiNetmask; // 接口对应的子网掩码
} INTERFACE_INFO;
实现的核心代码如下:
//
// 返回套接字信息结构体,参数type:type=-1表示列出所有网卡信息,不等于-1则是选择指定网卡显示
//
int GetIoInfo(int type)
{
int ret;
int nFace; // IoInfo个数
int i;
SOCKET InfoSock;
// 保存实际的网卡接口信息字节数
DWORD BytesReturned;
InfoSock=WSASocket(AF_INET,SOCK_DGRAM,0,0,0,0);
if(INVALID_SOCKET==InfoSock)
{
printf("WSASocket Error:%s\n",WSAGetLastError());
return 0;
}
// 设置标志SIO_GET_INTERFACE_LIST表示获取网络接口信息
ret=WSAIoctl(InfoSock,SIO_GET_INTERFACE_LIST,0,0,&IOInfo,sizeof(IOInfo),&BytesReturned,0,0);
if(SOCKET_ERROR==ret)
{
printf("WSAIoctl Error:%s\n",WSAGetLastError());
return 0;
}
// 计算网卡接口信息个数
nFace=BytesReturned/sizeof(INTERFACE_INFO);
// type=-1 -- List All Adapter Infomation
// type!=-1 -- List the Number [type] Adapter Information
switch(type)
{
case -1:
{
for(i=0;i<nFace;i++) // 循环输出所有网络接口信息
{
printf("\nThe %d NetInterFace Information:\n",i);
// 得到网卡地址,并将IP格式转换为字符串格式输出
printf("IP Address:%s\n",inet_ntoa(IOInfo[i].iiAddress.AddressIn.sin_addr));
}
return 1;
break;
}
default:
{
if(type<nFace&&type>=0){
printf("\nThe %d NetInterFace Information:\n",type);
// 得到网卡地址,并将IP格式转换为字符串格式输出
printf("IP Address:%s\n",inet_ntoa(IOInfo[type].iiAddress.AddressIn.sin_addr));
}else{
printf("The Net InteFace %d is Not Found!\n",type);
return 0;
}
return 1;
break;
}
}
return 1;
}
// 返回套接字信息结构体,参数type:type=-1表示列出所有网卡信息,不等于-1则是选择指定网卡显示
//
int GetIoInfo(int type)
{
int ret;
int nFace; // IoInfo个数
int i;
SOCKET InfoSock;
// 保存实际的网卡接口信息字节数
DWORD BytesReturned;
InfoSock=WSASocket(AF_INET,SOCK_DGRAM,0,0,0,0);
if(INVALID_SOCKET==InfoSock)
{
printf("WSASocket Error:%s\n",WSAGetLastError());
return 0;
}
// 设置标志SIO_GET_INTERFACE_LIST表示获取网络接口信息
ret=WSAIoctl(InfoSock,SIO_GET_INTERFACE_LIST,0,0,&IOInfo,sizeof(IOInfo),&BytesReturned,0,0);
if(SOCKET_ERROR==ret)
{
printf("WSAIoctl Error:%s\n",WSAGetLastError());
return 0;
}
// 计算网卡接口信息个数
nFace=BytesReturned/sizeof(INTERFACE_INFO);
// type=-1 -- List All Adapter Infomation
// type!=-1 -- List the Number [type] Adapter Information
switch(type)
{
case -1:
{
for(i=0;i<nFace;i++) // 循环输出所有网络接口信息
{
printf("\nThe %d NetInterFace Information:\n",i);
// 得到网卡地址,并将IP格式转换为字符串格式输出
printf("IP Address:%s\n",inet_ntoa(IOInfo[i].iiAddress.AddressIn.sin_addr));
}
return 1;
break;
}
default:
{
if(type<nFace&&type>=0){
printf("\nThe %d NetInterFace Information:\n",type);
// 得到网卡地址,并将IP格式转换为字符串格式输出
printf("IP Address:%s\n",inet_ntoa(IOInfo[type].iiAddress.AddressIn.sin_addr));
}else{
printf("The Net InteFace %d is Not Found!\n",type);
return 0;
}
return 1;
break;
}
}
return 1;
}
方法:C语言获取网卡方法之GetAdaptersInfo函数
接着上一篇,我们通过第二种方法实现,这种方法获取到信息更加完整,也比较实际应用。主要函数是GetAdaptersInfo,该函数在在头文件iphlpapi.h中提供的。但是有个问题该文件在默认只安装VC6.0的环境下是没有,他被包含在platform SDK(软件开发包)中,我从安装的SDK包提取出包含的文件头及相关文件直接放在开发目录下就可以了。在文章的最后会给出下载。
首先了解下GetAdaptersInfo函数:
DWORD GetAdaptersInfo(
// 接受数据的缓冲区,指向一个结构IP_ADAPTER_INFO
PIP_ADAPTER_INFO pAdapterInfo,
// 指向输出缓冲区的大小的指针
PULONG pOutBufLen
);
// 接受数据的缓冲区,指向一个结构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;
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 "stdafx.h"
#include "winsock.h"
#include "stdio.h"
#include "iphlpapi/iphlpapi.h" // GetAdaptersInfo()
#pragma comment(lib,"iphlpapi/iphlpapi.lib")
int main(int argc, char* argv[])
{
// 网络接口信息,最多20个
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)
{
printf("GetAdaptersInfo Error.\n");
return 0;
}else{
pIOInfo=IOInfo; // 将链表指针指向网络接口信息存储结构
while(pIOInfo!=NULL) // 不为空就循环读取网卡
{
static int Num;
Num++;
printf("\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[2],pIOInfo->Address[3],pIOInfo->Address[4],pIOInfo->Address[5]);
printf("│GateWay:%s\n",pIOInfo->GatewayList.IpAddress.String);
printf("└────────────Num.%d────────────┘\n",Num);
// 链表指针指向下一个
pIOInfo=pIOInfo->Next;
}
}
return 0;
}
#include "winsock.h"
#include "stdio.h"
#include "iphlpapi/iphlpapi.h" // GetAdaptersInfo()
#pragma comment(lib,"iphlpapi/iphlpapi.lib")
int main(int argc, char* argv[])
{
// 网络接口信息,最多20个
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)
{
printf("GetAdaptersInfo Error.\n");
return 0;
}else{
pIOInfo=IOInfo; // 将链表指针指向网络接口信息存储结构
while(pIOInfo!=NULL) // 不为空就循环读取网卡
{
static int Num;
Num++;
printf("\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[2],pIOInfo->Address[3],pIOInfo->Address[4],pIOInfo->Address[5]);
printf("│GateWay:%s\n",pIOInfo->GatewayList.IpAddress.String);
printf("└────────────Num.%d────────────┘\n",Num);
// 链表指针指向下一个
pIOInfo=pIOInfo->Next;
}
}
return 0;
}
方法三:hostent结构遍历
#include "stdio.h"
#include "winsock2.h"
#pragma comment(lib,"ws2_32.lib")
int main(int argc, char* argv[])
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return 0;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 ) {
WSACleanup( );
}
char host[255];
memset(host,0,255);
gethostname(host,255);
printf("%s\n",host);
struct hostent *Host;
Host=gethostbyname(host);
struct in_addr addr;
for(int i=0;;i++){
if(Host->h_addr_list[i]!='\0'){
memmove(&addr,Host->h_addr_list[i],4);
char *ip;
ip=inet_ntoa(addr);
printf("ip:%s\n",ip);
}else{
break;
}
}
WSACleanup();
return 0;
}
#include "winsock2.h"
#pragma comment(lib,"ws2_32.lib")
int main(int argc, char* argv[])
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return 0;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 ) {
WSACleanup( );
}
char host[255];
memset(host,0,255);
gethostname(host,255);
printf("%s\n",host);
struct hostent *Host;
Host=gethostbyname(host);
struct in_addr addr;
for(int i=0;;i++){
if(Host->h_addr_list[i]!='\0'){
memmove(&addr,Host->h_addr_list[i],4);
char *ip;
ip=inet_ntoa(addr);
printf("ip:%s\n",ip);
}else{
break;
}
}
WSACleanup();
return 0;
}