Windows网络编程技术[一]

Windows网络编程技术[一]

作者:Figo

从今天起,我们开始Windows平台下网络编程的学习。本篇主要讲解网络基础知识和本地主机网络相关信息查看涉及的API使用:

在开始进入后面的实际编程之前,首先需要掌握一些网络基本知识:如TCP/IP协议中网络分为层,应用层协议都有哪些等等。因为时间关系,我不可能 巨细无遗的把所有知识都说明,所以更多的还要靠自己去Google和看书。

在Windows中,获取和设定本地网络配置信息的API集是IP Helper,下面我以GetIfTable函数为例讲解它们的用法,其他函数的使用大同小异。

[code lang="cpp"]
//...figoyao.com
//适配器信息结构定义
typedef struct _FADAPTER_INFO
{
//接口列表次序
DWORD dwOrder;

//接口内部索引号
DWORD dwIndex;
//接口名称描述
char szName[MAX_INTERFACE_NAME_LEN];
//接口类型[本地回路/无线网卡/以太网卡/]
char szAdapterType[64];
//接口速度[Mbps为单位]
DWORD dwSpeed_Mbps;

//物理地址FF-FF-FF-FF-FF-FF
char szMAC_Addr[32];
//连接状态信息
char szOperStatus[64];

//发送和接收数据[bytes]
DWORD dwOUTData;
DWORD dwINData;

//IP地址和子网掩码
char szIP[32];
char szSubMask[32];

}FADAPTER_INFO,*PFADAPTER_INFO;
[/code]

下面的代码片段是获取适配器信息过程:

[code lang="cpp"]
//...figoyao.com
//获取网卡详细信息
PMIB_IFTABLE pstIfTable = NULL;
ULONG ulIfTable = 0;
GetIfTable(NULL,&ulIfTable,TRUE);
pstIfTable = (PMIB_IFTABLE)MALLOC(ulIfTable);
if (NULL == pstIfTable)
{
MessageBox(hwnd,"(PMIB_IFTABLE)MALLOC(ulIfTable)失败","错误",MB_OK|MB_ICONERROR);
SendMessage(hwnd,WM_CLOSE,0,0);
}
DWORD dwGetIfTableRet = GetIfTable(pstIfTable,&ulIfTable,TRUE);
if (NO_ERROR == dwGetIfTableRet)
{
if (pstIfTable->dwNumEntries != dwNumOfMac)
{
MessageBox(hwnd,"请报告你的Windows系统版本","错误",MB_OK|MB_ICONERROR);
SendMessage(hwnd,WM_CLOSE,0,0);
}
for (DWORD dwCnt = 0;dwCnt < pstIfTable->dwNumEntries;dwCnt++)
{
//索引号赋值[以0为起始]
pstAdapterInfo[dwCnt]->dwOrder = dwCnt;
pstAdapterInfo[dwCnt]->dwIndex = pstIfTable->table[dwCnt].dwIndex;
pstAdapterInfo[dwCnt]->dwSpeed_Mbps = pstIfTable->table[dwCnt].dwSpeed/1000000;
switch(pstIfTable->table[dwCnt].dwType)
{
//以太网适配器
case IF_TYPE_ETHERNET_CSMACD:
{
sprintf(pstAdapterInfo[dwCnt]->szAdapterType,"以太网适配器");
}
break;

//令牌环适配器
case IF_TYPE_ISO88025_TOKENRING:
{
sprintf(pstAdapterInfo[dwCnt]->szAdapterType,"令牌环适配器");
}
break;

//点到点协议适配器
case IF_TYPE_PPP:
{
sprintf(pstAdapterInfo[dwCnt]->szAdapterType,"点到点协议适配器");
}
break;

//An IEEE 802.11 wireless network interface
case IF_TYPE_IEEE80211:
{
sprintf(pstAdapterInfo[dwCnt]->szAdapterType,"IEEE 802.11无线网络适配器");
}
break;

//A tunnel type encapsulation network interface.
case IF_TYPE_TUNNEL:
{
sprintf(pstAdapterInfo[dwCnt]->szAdapterType,"管道网络适配器");
}
break;

//An ATM network interface.
case IF_TYPE_ATM:
{
sprintf(pstAdapterInfo[dwCnt]->szAdapterType,"ATM网络适配器");
}
break;

//A software loopback network interface.
case IF_TYPE_SOFTWARE_LOOPBACK:
{
sprintf(pstAdapterInfo[dwCnt]->szAdapterType,"软件回路适配器");
}
break;

//An IEEE 1394 (Firewire) high performance serial bus network interface.
case IF_TYPE_IEEE1394:
{
sprintf(pstAdapterInfo[dwCnt]->szAdapterType,"IEEE 1394高性能串口适配器");
}
break;

//光纤接口适配器
case MIB_IF_TYPE_FDDI:
{
sprintf(pstAdapterInfo[dwCnt]->szAdapterType,"光纤接口适配器");
}
break;

//串行适配器(Serial Line Interface Protocol)
case MIB_IF_TYPE_SLIP:
{
sprintf(pstAdapterInfo[dwCnt]->szAdapterType,"串行适配器(Serial Line Interface Protocol)");
}
break;

default:
{
sprintf(pstAdapterInfo[dwCnt]->szAdapterType,"其他类型适配器");
}
break;
}

//接口描述
sprintf(pstAdapterInfo[dwCnt]->szName,"%d->%s",dwCnt+1,pstIfTable->table[dwCnt].bDescr);
SendMessage(GetDlgItem(hwnd,IDC_CMB_ADAPTER),CB_ADDSTRING,0,(LPARAM)pstAdapterInfo[dwCnt]->szName);
//物理地址
if (0 == pstIfTable->table[dwCnt].dwPhysAddrLen)
{
sprintf(pstAdapterInfo[dwCnt]->szMAC_Addr,"00-00-00-00-00-00");
}
else
{
for (int j = 0;j < pstIfTable->table[dwCnt].dwPhysAddrLen;j++)
{
char szMACStr[6] = "";
if (j != pstIfTable->table[dwCnt].dwPhysAddrLen - 1)
{
sprintf(szMACStr,"%02x-",pstIfTable->table[dwCnt].bPhysAddr[j]);
}
else
{
sprintf(szMACStr,"%02x",pstIfTable->table[dwCnt].bPhysAddr[j]);
}
strcat(pstAdapterInfo[dwCnt]->szMAC_Addr,szMACStr);
}
}
//收发数据[bytes]
pstAdapterInfo[dwCnt]->dwINData = pstIfTable->table[dwCnt].dwInOctets;
pstAdapterInfo[dwCnt]->dwOUTData = pstIfTable->table[dwCnt].dwOutOctets;
}
}
else
{
char szTmpGetIfTableRet[32] = "";
sprintf(szTmpGetIfTableRet,"[错误代码:%d]GetIfTable失败",dwGetIfTableRet);
MessageBox(hwnd,szTmpGetIfTableRet,"错误",MB_OK|MB_ICONERROR);
SendMessage(hwnd,WM_CLOSE,0,0);
}
}
else
{
MessageBox(hwnd,"适配器接口数量获取失败","错误",MB_OK|MB_ICONERROR);
SendMessage(hwnd,WM_CLOSE,0,0);
}
//.............
[/code]

外网IP获取部分,这里的方法是通过访问一个脚本获取,通过http://figoyao.com/pip.php即 可获取客户端IP地址,在这个地址失败后,尝试http://figo.oni.cc/pip.php, 如果依旧失败则不再尝试:

[code lang="cpp"]
//...figoyao.com
/********************************************
*函数功能:
*获取本地主机在外网的IP地址
*入口参数:
*_out szPIP 接收外网IP的字符串地址
*
*返回值:
*成功:TRUE
*失败:FALSE
*
*注解:
*无
********************************************/
BOOL GetWANIPAddr(char *szPIP)
{
//1.1.1.1
if (NULL == szPIP)
{
return FALSE;
}

//检测网络状态
char szUrl[] = "http://www.baidu.com";
BOOL bState = InternetCheckConnection(szUrl,FLAG_ICC_FORCE_CONNECTION,0);
if (FALSE == bState)
{
return FALSE;
}

//获取公网IP的网址及备份网址
char szPIPUrl_Bak[] = "http://figoyao.com/pip.php";
char szPIPUrl[] = "http://figo.oni.cc/pip.php";

char szUserAgent[] = "figoyao/10.25 (Windows; U; Windows NT 6.4; zh-CN; rv:1.8.9) China/20121222";
//创建会话
HINTERNET hSession = InternetOpen(szUserAgent,INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);
if (NULL == hSession)
{
return FALSE;
}

HINTERNET hOpenUrl = NULL;
char szRequesHeader[] = "Accept: text/html\r\n";

hOpenUrl = InternetOpenUrl(hSession,szPIPUrl,szRequesHeader,strlen(szRequesHeader),\
INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_PRAGMA_NOCACHE|INTERNET_FLAG_RELOAD,0);

if (NULL == hOpenUrl)
{
//如果打开第一个网址失败则尝试通过备份网址获取公网IP
hOpenUrl = InternetOpenUrl(hSession,szPIPUrl_Bak,szRequesHeader,strlen(szRequesHeader),\
INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_PRAGMA_NOCACHE|INTERNET_FLAG_RELOAD,0);
if (NULL == hOpenUrl)
{
if (hSession)
{
InternetCloseHandle(hSession);
}
return FALSE;
}
goto getpip;
}

getpip:
{
//一次调用从服务器读取数据
DWORD dwNumOfBufRead = 0;
char lpGetIPBuf[32] = "";
BOOL bReadFile = InternetReadFile(hOpenUrl,lpGetIPBuf,32,&dwNumOfBufRead);

//检测读取的地址是否符合要求
if (dwNumOfBufRead > 32 || FALSE == bReadFile)
{
if (hSession)
{
InternetCloseHandle(hSession);
}
if (hOpenUrl)
{
InternetCloseHandle(hOpenUrl);
}
return FALSE;
}

// memset(szPIP,0,sizeof(szPIP));
DWORD dwTmpIPLen = strlen(lpGetIPBuf);
//接收的数据是以0+\r\n\r\n结尾,故减去5
strncpy(szPIP,lpGetIPBuf,dwTmpIPLen-5);
}

if (hSession)
{
InternetCloseHandle(hSession);
}
if (hOpenUrl)
{
InternetCloseHandle(hOpenUrl);
}
return TRUE;
}
[/code]

程序在Windows7测试未通过,但是控制台版本的没问题,究竟是何原因暂时没有深究。这次是使用VS2003编译的

源码:点击 下载

转载请注明出处:http://www.figoyao.com/blog/2010/04/25/1352

你可能感兴趣的:(Windows网络编程技术[一])