多网卡获取IP之VC篇

方法: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 // 操作结束后调用的历程指针
);


该函数定义在ws2tcpip.h中所以要先包含该头文件,另外需要提到的就是存储信息结构体,如下:

typedef struct _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;
}

方法:C语言获取网卡方法之GetAdaptersInfo函数
接着上一篇,我们通过第二种方法实现,这种方法获取到信息更加完整,也比较实际应用。主要函数是GetAdaptersInfo,该函数在在头文件iphlpapi.h中提供的。但是有个问题该文件在默认只安装VC6.0的环境下是没有,他被包含在platform SDK(软件开发包)中,我从安装的SDK包提取出包含的文件头及相关文件直接放在开发目录下就可以了。在文章的最后会给出下载。
首先了解下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 "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;
}

方法三: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;
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值