实现HTTP访问的流程包括以下几步: 
1, 首先我们打开一个Session获得一个HINTERNET session句柄; 
2, 然后我们使用这个session句柄与服务器连接得到一个HINTERNET connect句柄; 
3, 然后我们使用这个connect句柄来打开Http请求得到一个HINTERNET request句柄; 
4, 这时我们就可以使用这个request句柄来发送数据与读取从服务器返回的数据; 
5, 最后依次关闭request,connect,session句柄。

微软提供了两套http访问的接口:WinHTTP和WinINet。WinHTTP比WinINet更加安全和健壮,可以认为WinHTTP是WinINet的升级版本。这两套API包含了很多相似的函数与宏定义,访问的流程也是完全类似的(上述5步)。本文主要通过WinHTTP实现post请求方法,严格按照上述5个步骤给大家进行讲解。 
又由于我所接收到的数据是UTF8而不是ASCII码,因此一开始接收到的数据存在乱码。在下述代码中我会详细解释出现乱码的原因以及如何解决。 
好,小二,上代码!
---------------------

#include "stdafx.h"
#include "jsonparser.h"#include <string>
#include <windows.h>
#include <winhttp.h>
#pragma comment(lib, "winhttp.lib")int _tmain(int argc, _TCHAR* argv[])
{HINTERNET hSession = NULL;HINTERNET hConnect = NULL;HINTERNET hRequest = NULL;//1. 初始化一个WinHTTP-session句柄,参数1为此句柄的名称hSession = WinHttpOpen(L"csdn@elaine_bao", NULL, NULL, NULL, NULL);if (hSession == NULL) {cout<<"Error:Open session failed: "<<GetLastError()<<endl;return -1;}//2. 通过上述句柄连接到服务器,需要指定服务器IP和端口号。若连接成功,返回的hConnect句柄不为NULLhConnect = WinHttpConnect(hSession, L"192.168.50.112", (INTERNET_PORT)8080, 0);if (hConnect == NULL) {cout << "Error:Connect failed: " << GetLastError()<<endl;return -1;}//3. 通过hConnect句柄创建一个hRequest句柄,用于发送数据与读取从服务器返回的数据。hRequest = WinHttpOpenRequest(hConnect, L"Post", L"getServiceInfo", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);//其中参数2表示请求方式,此处为Post;参数3:给定Post的具体地址,如这里的具体地址为http://192.168.50.112/getServiceInfoif (hRequest == NULL) {cout << "Error:OpenRequest failed: " << GetLastError() << endl;return -1;}//4-1. 向服务器发送post数据//(1) 指定发送的数据内容string data = "This is my data to be sent"; const void *ss = (const char *)data.c_str();//(2) 发送请求BOOL bResults;bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, const_cast<void*>(ss), data.length(), data.length(), 0);if (!bResults){cout << "Error:SendRequest failed: " << GetLastError() << endl;return -1;}else{//(3) 发送请求成功则准备接受服务器的response。注意:在使用 WinHttpQueryDataAvailable和WinHttpReadData前必须使用WinHttpReceiveResponse才能access服务器返回的数据bResults = WinHttpReceiveResponse(hRequest, NULL);}//4-2. 获取服务器返回数据的header信息。这一步我用来获取返回数据的数据类型。LPVOID lpHeaderBuffer = NULL;DWORD dwSize = 0;   if (bResults){//(1) 获取header的长度WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF,WINHTTP_HEADER_NAME_BY_INDEX, NULL,&dwSize, WINHTTP_NO_HEADER_INDEX);//(2) 根据header的长度为buffer申请内存空间if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){lpHeaderBuffer = new WCHAR[dwSize / sizeof(WCHAR)];//(3) 使用WinHttpQueryHeaders获取header信息bResults = WinHttpQueryHeaders(hRequest,WINHTTP_QUERY_RAW_HEADERS_CRLF,WINHTTP_HEADER_NAME_BY_INDEX,lpHeaderBuffer, &dwSize,WINHTTP_NO_HEADER_INDEX);}}printf("Header contents: \n%S", lpHeaderBuffer);//解析上述header信息会发现服务器返回数据的charset为uft-8。这意味着后面需要对获取到的raw data进行宽字符转换。一开始由于没有意识到需要进行转换所以得到的数据都是乱码。//出现乱码的原因是:HTTP在传输过程中是二值的,它并没有text或者是unicode的概念。HTTP使用7bit的ASCII码作为HTTP headers,但是内容是任意的二值数据,需要根据header中指定的编码方式来描述它(通常是Content-Type header).//因此当你接收到原始的HTTP数据时,先将其保存到char[] buffer中,然后利用WinHttpQueryHearders()获取HTTP头,得到内容的Content-Type,这样你就知道数据到底是啥类型的了,是ASCII还是Unicode或者其他。//一旦你知道了具体的编码方式,你就可以通过MultiByteToWideChar()将其转换成合适编码的字符,存入wchar_t[]中。//关于乱码的解决方案请看4-4//4-3. 获取服务器返回数据LPSTR pszOutBuffer = NULL;DWORD dwDownloaded = 0;         //实际收取的字符数wchar_t *pwText = NULL;if (bResults){do{//(1) 获取返回数据的大小(以字节为单位)dwSize = 0;if (!WinHttpQueryDataAvailable(hRequest, &dwSize)){cout << "Error:WinHttpQueryDataAvailable failed:" << GetLastError() << endl;break;}           if (!dwSize)    break;  //数据大小为0                //(2) 根据返回数据的长度为buffer申请内存空间pszOutBuffer = new char[dwSize + 1];if (!pszOutBuffer){cout<<"Out of memory."<<endl;break;}ZeroMemory(pszOutBuffer, dwSize + 1);       //将buffer置0//(3) 通过WinHttpReadData读取服务器的返回数据if (!WinHttpReadData(hRequest,pszOutBuffer, dwSize, &dwDownloaded)){cout << "Error:WinHttpQueryDataAvailable failed:" << GetLastError() << endl;}if (!dwDownloaded)break;} while (dwSize > 0);//4-4. 将返回数据转换成UTF8DWORD dwNum = MultiByteToWideChar(CP_ACP, 0, pszOutBuffer, -1, NULL, 0);    //返回原始ASCII码的字符数目       pwText = new wchar_t[dwNum];                                                //根据ASCII码的字符数分配UTF8的空间MultiByteToWideChar(CP_UTF8, 0, pszOutBuffer, -1, pwText, dwNum);           //将ASCII码转换成UTF8printf("Received contents: \n%S", pwText);}//5. 依次关闭request,connect,session句柄if (hRequest) WinHttpCloseHandle(hRequest);if (hConnect) WinHttpCloseHandle(hConnect);if (hSession) WinHttpCloseHandle(hSession);return 0;
}

C++编程笔记:使用WinHTTP实现HTTP访问(解决接收UTF8数据乱码问题)相关推荐

  1. NDK 高级编程(笔记)

    Android 开发中针对 NDK 的书籍很少,<Pro Android C++ with the NDK>也是出版的比较早的一本书,有些内容可能对现在的开发并不适用.但是书中介绍的内容比 ...

  2. Java TCP/IP Socket 编程 笔记

    http://jimmee.iteye.com/blog/617110 http://jimmee.iteye.com/category/93740 Java TCP/IP Socket 编程 笔记( ...

  3. java并发编程笔记_java并发编程笔记(一)——并发编程简介

    java并发编程笔记(一)--简介 线程不安全的类示例 public class CountExample1 { // 请求总数 public static int clientTotal = 500 ...

  4. Java编程笔记7:内部类

    Java编程笔记7:内部类 图源:PHP中文网 所谓的内部类,其实就是定义在类中的类.这和Java编程笔记6:接口 - 魔芋红茶's blog (icexmoon.xyz)中提到的接口嵌套的方式有点相 ...

  5. Java编程笔记16:深入容器

    Java编程笔记16:深入容器 图源:PHP中文网 填充容器 填充容器会有Java编程笔记15:数组 - 魔芋红茶's blog (icexmoon.cn)种提到的填充数组同样的问题. 和数组类似,标 ...

  6. Java编程笔记2:初始化和清理

    Java编程笔记2:初始化和清理 图源:Java Switch语句(用法详解)-java教程-PHP中文网 构造器 构造器,在编程领域也会被称作构造函数.事实上我觉得这个名称并不是很恰当,可能相当一部 ...

  7. Java编程笔记6:接口

    Java编程笔记6:接口 图源:PHP中文网 在Java中,接口可能只是特指使用interface关键字声明的一种抽象类型,但实际上在UML或者OOP中,接口往往是作为一种底层抽象概念而言的,其具体实 ...

  8. Java编程笔记9:容器(下)

    Java编程笔记9:容器(下) 图源:PHP中文网 本篇文章是Java编程笔记8:容器(上) - 魔芋红茶's blog (icexmoon.xyz)的下篇. Set Set也是一种常见的数据类型,很 ...

  9. Java并发编程笔记(1)基础知识

    Java并发编程的三个性质 原子性 *在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行. *只有形如x = 10这种不可再分的赋值操作才有 ...

最新文章

  1. 运维监控系统——配置服务监控项(Http,Nginx,MySQL)
  2. 选择图层_Photoshop思维导图,图层的高级操作
  3. Python-高阶函数
  4. apache rewrite规则详解
  5. dict()与{},list()与[]性能对比
  6. 最常用的ES6特性(转)
  7. 图神经网络(二)GCN的性质(3)GCN是一个低通滤波器
  8. [html] 你知道什么是粘性布局吗?
  9. 基础算法学习(二)_二叉树及应用赫夫曼编码
  10. 经纬度坐标与距离的相互转换及其实现
  11. [Git]Git远程仓库
  12. matlab 遗传算法 等式约束,关于MATLAB遗传算法工具箱不等式约束
  13. 静态网页制作前夕小记录
  14. Win10使用Dism命令提取(备份)和还原驱动程序
  15. dirent struct_struct dirent中d_name长度问题
  16. Kotlin-三目表达式Kotlin版
  17. csharp基础练习题:过滤列表【难度:1级】--景越C#经典编程题库,不同难度C#练习题,适合自学C#的新手进阶训练
  18. visual studio出现的0xc0000135问题
  19. NTL密码算法开源库——模二整数上的矩阵(mat_GF2)
  20. face++旷世科技实习生面试

热门文章

  1. ACM解题的一些技巧和方法
  2. Dao跨事务调用实现转账功能
  3. 乔布斯一生都在模仿的偶像:两度从哈佛大学退学的发明家Edwin H. Land
  4. 定义符号常量pi.const float pi= 3.1415926f; 这句话是否正确
  5. 正点原子DS100拆解全过程-硬件工程师必备
  6. (C语言)字符串函数strcpy和strlen的实现,以及简单的文字编程题(派大星看了都会写)
  7. l7sa008b故障代码_麦克维尔空调故障代码速查
  8. 基本的安全和HTTP认证
  9. 对偶量子计算机,斯坦福大学:通过时空对偶性探索量子纠缠的动力学
  10. 算法练习贴--32--找不同(Java)