C++实现简单的HTTP客户端(阻塞方式)

来源:互联网 发布:海外淘软件知乎 编辑:程序博客网 时间:2024/06/08 05:09

项目中用到的HTTP请求功能,自己简单写了个客户端,实现了POST方式,GET方式实现应该也很简单(空接口已经写好:=))。

应该支持多线程(这个很重要)。

HttpClient.h

#ifndef _HTTP_CLIENT_H_#define _HTTP_CLIENT_H_#define HTTP_DEFAULT_REQUEST_TIMEOUT(60*1000)#define HTTP_DEFAULT_PORT80#define HTTP_SEND_BUF_LEN2048#define HTTP_RECV_BUF_LEN2048class HttpClient{public:HttpClient();~HttpClient();public:/*********************************************************************功能:以阻塞方式发送一个HTTP请求,并返回请求结果返回值:返回发送成功或者失败参数:url请求的HTTP url,不能为空。  post_data POST数据,可以为空,如果为空,则使用GET方式发送。  time_out   发送超时时间,如果为0,则使用默认值  ret_buf    请求返回结果缓冲区  ret_len    请求返回结果缓冲区长度***********************************************************************/bool Send(const char* url, const char* post_data, const int time_out, char* ret_buf, int* ret_len);private:charm_strIP[MAX_PATH];/*HTTP服务器地址*/intm_iPort;/*HTTP服务器端口*/charm_strAction[MAX_PATH];/*HTTP请求的动作*/intm_iTimeOut;/*HTTP请求超时时间*/SOCKETm_sock;/*TCP 套接字*//*********************************************************************功能:实现TCP连接HTTP服务器返回值:返回发送成功或者失败参数:空***********************************************************************/bool TCP_Connect();/*********************************************************************功能:实现TCP连接关闭返回值:空参数:空***********************************************************************/void TCP_Close();/*********************************************************************功能:设置阻塞TCP连接的超时时间返回值:返回发送成功或者失败参数:空***********************************************************************/bool TCP_SetTimeout();/*********************************************************************功能:解析URL中的IP地址,端口,文件名等。返回值:返回发送成功或者失败参数:url请求的HTTP url,不能为空。***********************************************************************/bool ParserUrl(const char* url);/*********************************************************************功能:实现HTTP POST方法返回值:返回发送成功或者失败参数:post_data POST数据,不能为空  ret_buf HTTP返回数据  ret_len HTTP返回数据长度***********************************************************************/bool Post(const char* post_data, char* ret_buf, int* ret_len);/*********************************************************************功能:实现HTTP GET方法返回值:返回发送成功或者失败参数:ret_buf HTTP返回数据  ret_len HTTP返回数据长度***********************************************************************/bool Get(char* ret_buf, int* ret_len);/*********************************************************************功能:生成POST方法的HTTP包返回值:空参数:post_data POST数据  buf HTTP数据缓冲区  buf_len 传入缓冲区长度,传出HTTP数据长度***********************************************************************/void MakePostBuf(const char* post_data, char* buf, int* buf_len);/*********************************************************************功能:初始化Win32网络库返回值:空参数:空***********************************************************************/inline void InitWin32NetLib(){WSADATA wsa_data;WSAStartup(MAKEWORD(2,0), &wsa_data);}/*********************************************************************功能:注销Win32网络库返回值:空参数:空***********************************************************************/inline void UnInitWin32NetLib(){WSACleanup();}private:static char* m_post_header;static char* m_get_header;public:static HttpClient* GetInstance();private:static HttpClient m_oInstance;};#endif


HttpClient.cpp

#include "stdafx.h"#include "HttpClient.h"#include <Log/MyLogEx.h>HttpClient HttpClient::m_oInstance;HttpClient* HttpClient::GetInstance(){return &m_oInstance;}char* HttpClient::m_post_header = "POST %s HTTP/1.1\r\n"    "Accept: image/gif, image/jpeg, */*\r\nAccept-Language: zh-cn\r\n"    "Accept-Encoding: gzip, deflate\r\nHost: %s:%d\r\n""Content-Type: application/json\r\nContent-Length: %d\r\n"    "User-Agent: HLS Slice Service\r\nConnection: Keep-Alive\r\n\r\n%s";char* HttpClient::m_get_header = "GET %s HTTP/1.1\r\n"    "Accept: image/gif, image/jpeg, */*\r\nAccept-Language: zh-cn\r\n"    "Accept-Encoding: gzip, deflate\r\nHost: %s:%d\r\n"    "User-Agent: HLS Slice Service\r\nConnection: Keep-Alive\r\n\r\n";HttpClient::HttpClient(): m_iPort(HTTP_DEFAULT_PORT),  m_iTimeOut(HTTP_DEFAULT_REQUEST_TIMEOUT),  m_sock(INVALID_SOCKET){memset(m_strIP, 0, sizeof(m_strIP));memset(m_strAction, 0, sizeof(m_strAction));InitWin32NetLib();}HttpClient::~HttpClient(){if(m_sock != INVALID_SOCKET){closesocket(m_sock);m_sock = INVALID_SOCKET;}UnInitWin32NetLib();}bool HttpClient::Send(const char* url, const char* post_data, const int time_out, char* ret_buf, int* ret_len){if(url == NULL || ret_buf == NULL || *ret_len == 0){return false;}if(!ParserUrl(url)){LOG_PRINTEX(0, MyLogEx::LOG_LEVEL_DEBUG_4, "Parser HTTP URL failed!");return false;}//LOG_PRINTEX(0, MyLogEx::LOG_LEVEL_DEBUG_4, "HTTP IP=%s, port=%d, filename=%s",//m_strIP, m_iPort, m_strAction);m_iTimeOut = (time_out == 0 ? HTTP_DEFAULT_REQUEST_TIMEOUT : time_out);if(post_data){return Post(post_data, ret_buf, ret_len);}return Get(ret_buf, ret_len);}bool HttpClient::ParserUrl(const char* url){char szBuf[1024] = {0};strncpy_s(szBuf, sizeof(szBuf)-1, url, sizeof(szBuf)-1);int length = 0;char port_buf[20];char *buf_end = (char *)(szBuf + strlen(szBuf));char *begin, *host_end, *colon, *question_mark;/* 查找主机的开始位置 */begin = strstr(szBuf, "//");begin = (begin ? begin + 2 : szBuf);colon = strchr(begin, ':');host_end = strchr(begin, '/');if(host_end == NULL){host_end = buf_end;}else{   /* 得到文件名 */question_mark = strchr(host_end, '?');if(question_mark != NULL){strncpy_s(m_strAction, MAX_PATH-1, host_end, question_mark-host_end);}else{strncpy_s(m_strAction, MAX_PATH-1, host_end, strlen(host_end));}}if(colon) /* 得到端口号 */{colon++;length = host_end - colon;memcpy(port_buf, colon, length);port_buf[length] = 0;m_iPort = atoi(port_buf);host_end = colon - 1;}else{m_iPort = HTTP_DEFAULT_PORT;}/* 得到主机信息 */length = host_end - begin;length = (length > MAX_PATH  ? MAX_PATH : length);memcpy(m_strIP, begin, length);m_strIP[length] = 0;return true;}void HttpClient::MakePostBuf(const char* post_data, char* buf, int* buf_len){sprintf_s(buf, *buf_len, m_post_header, m_strAction, m_strIP, m_iPort, strlen(post_data), post_data);*buf_len = strlen(buf);//LOG_PRINTEX(0, MyLogEx::LOG_LEVEL_DEBUG_4, "POST Data=%s", buf);}bool HttpClient::TCP_SetTimeout(){int TimeOut=m_iTimeOut;if(::setsockopt(m_sock, SOL_SOCKET, SO_SNDTIMEO,(char *)&TimeOut, sizeof(TimeOut))==SOCKET_ERROR){LOG_PRINTEX(0, MyLogEx::LOG_LEVEL_DEBUG_4, "TCP设置发送超时失败!");return false;}if(::setsockopt(m_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&TimeOut, sizeof(TimeOut))==SOCKET_ERROR){LOG_PRINTEX(0, MyLogEx::LOG_LEVEL_DEBUG_4, "TCP设置接收超时失败!");return false;}return true;}bool HttpClient::TCP_Connect(){int result = 0;struct sockaddr_in serv_addr;serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons((u_short)m_iPort);serv_addr.sin_addr.s_addr = inet_addr(m_strIP);m_sock = socket(AF_INET, SOCK_STREAM, 0); if(m_sock == INVALID_SOCKET){LOG_PRINTEX(0, MyLogEx::LOG_LEVEL_DEBUG_4, "socket() 调用失败!错误码=%d", WSAGetLastError());return false;}if(!TCP_SetTimeout()){return false;}result = connect(m_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));if(result == SOCKET_ERROR){closesocket(m_sock);m_sock = INVALID_SOCKET;//LOG_PRINTEX(0, MyLogEx::LOG_LEVEL_DEBUG_4, "连接失败!错误码=%d", WSAGetLastError());return false; }return true;}void HttpClient::TCP_Close(){closesocket(m_sock);m_sock = INVALID_SOCKET;}bool HttpClient::Post(const char* post_data, char* ret_buf, int* ret_len){int iRet;char strSendBuf[HTTP_SEND_BUF_LEN] = {0};int iSendLen = HTTP_SEND_BUF_LEN;MakePostBuf(post_data, strSendBuf, &iSendLen);if(!TCP_Connect()){return false;}iRet = send(m_sock, strSendBuf, iSendLen, 0);if (iRet == SOCKET_ERROR){LOG_PRINTEX(0, MyLogEx::LOG_LEVEL_DEBUG_4, "发送数据失败!错误码=%d", WSAGetLastError());TCP_Close();return false; }int recv_len = *ret_len;iRet = recv(m_sock, ret_buf, recv_len, 0);if(iRet > 0){*ret_len = iRet;}else if(iRet == 0){//LOG_PRINTEX(0, MyLogEx::LOG_LEVEL_DEBUG_4, "Server close connection");}else{//LOG_PRINTEX(0, MyLogEx::LOG_LEVEL_DEBUG_4, "error == %d", WSAGetLastError());*ret_len = 0;}TCP_Close();return true;}bool HttpClient::Get(char* ret_buf, int* ret_len){return false;}


代码下载(实现了GET方法和URL编码的代码):http://download.csdn.net/download/fang437385323/9942803


阅读全文
0 0