今天分享下 关于网络的代码 在windows平台下 基于 wininet 网络库 以HTTP / HTTPS 访问 服务器的接口
很多人开发 都卡在了这一步
#include <WinInet.h> // 加载 网络模块 #pragma comment(lib,"Wininet.lib")
#include "tinystr.h" // 加载解析XML模块 #include "tinyxml.h"
#include "stdafx.h" #include <iostream> #include <Windows.h> #include <atlstr.h> #include <string>
#include "md5.h" using namespace std;
// 网络地址 IP 或者 网址 网址不要加 http:// 直接www #ifdef UNICDOE wchar_t *g_strUrl2 = L"10.110.110.100"; #else char *g_strUrl2 = "<span style="font-family: Arial, Helvetica, sans-serif;">10.110.110.100</span>"; #endif
int g_nPort = 8080; // 网络链接 端口 string g_strCurVersion = "1.0.27"; // 当前版本号 这个可以写到 资源里/配置文件里/注册表里 等 我这里为了方便写在了全局变量
typedef struct UpdateInfoParam { string strVersion; string strUrl; string strPath; string strName; string strMd5; string strSize; string strLog; }UpdateInfo;
// UTF8 ----- UNICODE 转码 CString UTF8toUnicode(LPCSTR pszStr) { if (!pszStr) return _T(""); //预转换,计算需要的空间 int wstrlen = ::MultiByteToWideChar(CP_UTF8, NULL, pszStr, strlen(pszStr), NULL, 0); if( wstrlen == 0 ) { return CString(_T("")); } ++wstrlen; WCHAR *wp = new WCHAR[wstrlen]; ::ZeroMemory(wp, (wstrlen)*sizeof(WCHAR)); //转换 int ret = ::MultiByteToWideChar(CP_UTF8, NULL, pszStr, strlen(pszStr), wp, wstrlen); if( ret != 0 ) { CString s = wp ; delete[] wp ; return s ; } //保存并返回 delete[] wp ; return CString(_T("")); ; }
// 这个方法 是 集 网络请求 XML 解析 于一体 把XML解析出来的结果 保存到了 g_UpdateInfo 结构体里面 int UpdateModuleMethod() { HINTERNET hSession = NULL; // WININET 回话句柄 HINTERNET hConnect = NULL;// WININET 链接句柄 HINTERNET hRequest = NULL;// WININET 请求句柄 INTERNET_BUFFERS g_hNetBuf; char *psz =NULL; //string strXmluni=""; // XMLsh TCHAR szFilePath[MAX_PATH]; // 访问网页的XML hSession = InternetOpenA("UpdateModule",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0); assert(hSession != NULL); hConnect = InternetConnectA(hSession,g_strUrl2,g_nPort,NULL,NULL,INTERNET_SERVICE_HTTP,0,0); assert(hConnect != NULL); DWORD dwOpenRequestFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS | INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_NO_AUTO_REDIRECT | INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD; const char *pStr = "hxsp/update/admin/ver.xml"; hRequest = HttpOpenRequestA(hConnect,"GET",pStr,"HTTP/1.1",NULL,NULL,dwOpenRequestFlags,0); if (hRequest != NULL) { if(!HttpSendRequestA(hRequest,NULL,0,NULL,0)) // 链接超时 { return 0; } } char szBuffer[2048] = {0}; DWORD dwLen = 2048; HttpQueryInfoA(hRequest,HTTP_QUERY_STATUS_CODE,szBuffer,&dwLen,NULL); if (strcmp(szBuffer,"200") != 0) // 服务器未响应 { if (strcmp(szBuffer,"404") == 0) { MessageBox(NULL,L"网络异常",L"网络提示",MB_OK); exit(0); } return 1; } else // 网络请求正常 进行下面的代码 { DWORD dwInforLevel = HTTP_QUERY_RAW_HEADERS_CRLF; DWORD dwInfoBufferLength = 10; char *pInfoBuffer = (char *)malloc(dwInfoBufferLength+1); while (!HttpQueryInfoA(hRequest,dwInforLevel,pInfoBuffer,&dwInfoBufferLength,NULL)) { DWORD dwErr = GetLastError(); if (dwErr == ERROR_INSUFFICIENT_BUFFER) { free(pInfoBuffer); pInfoBuffer = (char *)malloc(dwInfoBufferLength+1); } } pInfoBuffer[dwInfoBufferLength] = '\n\r\0'; char *str = pInfoBuffer; free(pInfoBuffer); DWORD dwBytesAvailble; if(InternetQueryDataAvailable(hRequest,&dwBytesAvailble,0,0)) // 读取 服务器 返回数据 { dwBytesAvailble = dwBytesAvailble + (4597 - dwBytesAvailble); char *pMessageBody = (char *)malloc(dwBytesAvailble); memset(pMessageBody,0,dwBytesAvailble); DWORD dwBytesRead; BOOL bResult = InternetReadFile(hRequest,pMessageBody,dwBytesAvailble,&dwBytesRead); // 保存服务器返回数据 CString strXml = UTF8toUnicode(pMessageBody); psz = (char *)malloc(strlen(pMessageBody)+1); strcpy(psz,pMessageBody); char *pCurDir; int nLen = WideCharToMultiByte(CP_ACP,0,strXml,-1,NULL,0,NULL,NULL); int i = (int)wcslen(strXml)*sizeof(TCHAR); pCurDir = new char[i+1]; if (!pCurDir) // 如果申请内存失败 重新再申请一次 { pCurDir = new char[i+1]; } if(!pCurDir) { return 0; } WideCharToMultiByte(CP_ACP,0,strXml,-1,pCurDir,nLen,NULL,NULL); CStringA strXmlA(strXml.GetBuffer()); string strXmluni = strXmlA.GetBuffer(0); } } InternetCloseHandle(hRequest); InternetCloseHandle(hConnect); InternetCloseHandle(hSession); // 关闭 网络请求句柄 防止内存泄露 hSession = hConnect = hRequest = NULL; // 句柄清零 // 解析XML CString strXml = UTF8toUnicode(psz); CStringA strXmlA(strXml.GetBuffer()); string strXmluni = strXmlA.GetBuffer(0); TiXmlDocument *myDocument = new TiXmlDocument(); myDocument->Parse(strXmluni.c_str(),0,TIXML_ENCODING_LEGACY); TiXmlElement *RootElement = myDocument->RootElement(); while(RootElement) { TiXmlElement *pTaskGroup1 = RootElement->FirstChildElement(); while(pTaskGroup1) { if (pTaskGroup1->GetText() !=NULL) { //std::cout << pTaskGroup1->Value()<< " : " << pTaskGroup1->GetText() << std::endl; if (strcmp(pTaskGroup1->Value(),"ver")==0) { g_UpdateInfo.strVersion = pTaskGroup1->GetText(); } else if(strcmp(pTaskGroup1->Value(),"url")==0) { g_UpdateInfo.strUrl = pTaskGroup1->GetText(); } else if(strcmp(pTaskGroup1->Value(),"log")==0) { g_UpdateInfo.strLog = pTaskGroup1->GetText(); } } if (strcmp(pTaskGroup1->Value(),"download")==0) { TiXmlElement *pTaskChildGroup = pTaskGroup1->FirstChildElement(); while(pTaskChildGroup) { if (strcmp(pTaskChildGroup->Value(),"file")==0) { TiXmlElement *pTaskChildGroup2 = pTaskChildGroup->FirstChildElement(); while (pTaskChildGroup2) { if (strcmp(pTaskChildGroup2->Value(),"path")==0) { g_UpdateInfo.strPath = pTaskChildGroup2->GetText(); } else if(strcmp(pTaskChildGroup2->Value(),"name")==0) { g_UpdateInfo.strName = pTaskChildGroup2->GetText(); } else if (strcmp(pTaskChildGroup2->Value(),"md5")==0) { g_UpdateInfo.strMd5 = pTaskChildGroup2->GetText(); } else if (strcmp(pTaskChildGroup2->Value(),"size")==0) { g_UpdateInfo.strSize = pTaskChildGroup2->GetText(); } pTaskChildGroup2 = pTaskChildGroup2->NextSiblingElement(); } } pTaskChildGroup = pTaskChildGroup->NextSiblingElement(); } } pTaskGroup1 = pTaskGroup1->NextSiblingElement(); } RootElement = RootElement->NextSiblingElement(); } return 0; }
int _tmain(int argc, _TCHAR* argv[]) { int n = GetTickCount(); UpdateModuleMethod(); // 调用 网络请求函数 int m = GetTickCount(); int nRes = m - n ; // nRes 结果是 运行这段 访问网络请求代码 所消耗的 毫秒数 if (strcmp(g_UpdateInfo.strVersion.c_str(),g_strCurVersion.c_str())==0) // 如果本地版本 和 服务器版本一直 则不更新 { MessageBox(0,L"已经是最新版本",L"更新提示",MB_OK); } else { // 打开本地的 要更新的文件 const char *fileName="D:\\hxsp.exe"; HANDLE hFile =CreateFileA(fileName,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); DWORD dwReadSize = 0; DWORD filesize = GetFileSize(hFile, NULL); char *buffer = new char[filesize+1]; ReadFile(hFile,buffer,filesize,&dwReadSize,NULL); CloseHandle(hFile); MD5 iMD5; iMD5.GenerateMD5(buffer, filesize); string result = iMD5.ToString(); // 本地文件的MD5值 delete []buffer; if(strcmp(g_UpdateInfo.strMd5.c_str(),result.c_str())==0) { // 即使 本地版本 和 服务器版本不一致 ,但是 文件的MD5是一致的 所以不更新 } else { // MD5不一致了 更新文件 更新文件之前 一定要关闭这个文件 string strDownloadUrl = g_UpdateInfo.strUrl+g_UpdateInfo.strPath+g_UpdateInfo.strName; URLDownloadToFileA(0,strDownloadUrl.c_str(),"D:\\hxsp.exe",0,0); // 执行到这里 代表更新成功 再对比一次 本地和服务器的MD5值 const char *fileName="D:\\hxsp.exe"; HANDLE hFile =CreateFileA(fileName,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); DWORD dwReadSize = 0; DWORD filesize = GetFileSize(hFile, NULL); char *buffer = new char[filesize+1]; ReadFile(hFile,buffer,filesize,&dwReadSize,NULL); CloseHandle(hFile); MD5 iMD5; iMD5.GenerateMD5(buffer, filesize); string result = iMD5.ToString(); // 本地文件的MD5值 delete []buffer; if(strcmp(g_UpdateInfo.strMd5.c_str(),result.c_str())==0) { // 如果一致 代表更新成功 MessageBox(0,L"更新成功",L"更新提示",MB_OK); } } } return 0; }
代码是我从很久之前一个工程里 COPY 出来的 可以实现和 HTTP服务器的接口交互
源码下载地址 是:
http://download.csdn.net/detail/innovation_miracle/9411552
接下来我应该有时间 还会写一些 代码分享的文章
1. 我会分享 我自己 基于WTL 开发写的界面库
2. 基于 Libevent 库的相关使用和说明
3. 软件调试的方法