项目中用到的HTTP请求功能,自己简单写了个客户端,实现了POST方式,GET方式实现应该也很简单(空接口已经写好:=))。
应该支持多线程(这个很重要)。
HttpClient.h
#ifndef _HTTP_CLIENT_H_
#define _HTTP_CLIENT_H_
#define HTTP_DEFAULT_REQUEST_TIMEOUT (60*1000)
#define HTTP_DEFAULT_PORT 80
#define HTTP_SEND_BUF_LEN 2048
#define HTTP_RECV_BUF_LEN 2048
class 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:
char m_strIP[MAX_PATH]; /*HTTP服务器地址*/
int m_iPort; /*HTTP服务器端口*/
char m_strAction[MAX_PATH]; /*HTTP请求的动作*/
int m_iTimeOut; /*HTTP请求超时时间*/
SOCKET m_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