/*****************************************************************/
//name : myhttp.h
//function : http 请求
//copyright :
//author : mark
//date : 2008-05-13
/**************************************************************/
#ifndef _MY_HTTP_INCLUDE_
#define _MY_HTTP_INCLUDE_
#include <string>
#include <map>
#include <vector>
class CAutoMem;
#ifdef WIN32
#include "WINSOCK2.H"
#include <io.h>
#endif
class CMyHttp
{
private:
#ifdef WIN32
SOCKET m_fd;
typedef SOCKET mysocket;
#else
int m_fd;
typedef unsigned int mysocket;
#endif
#ifdef WIN32
#define MY_INVALID_SOCKET INVALID_SOCKET
#else
#define MY_INVALID_SOCKET -1
#endif
#ifdef WIN32
#define MY_SOCKET_ERROR SOCKET_ERROR
#else
#define MY_SOCKET_ERROR -1
#endif
#ifdef WIN32
#define MYERRNO ::WSAGetLastError()
#else
#define MYERRNO errno
#endif
//超时最大值基数(单位毫秒)
int m_timeoutmillisecond;
//超时最小基数(单位:微秒,100000微秒,也即100毫秒)
const int m_basicmicrosecond;
//最大尝试次数
const int MAXIMUMERRORNUMBER;
//发送的请求原始串
std::string m_req;
//服务器 IP 和 port 对应表
std::string m_srvip;
int m_srvport;
int closesock(mysocket connectsocket);
void release();
//发送数据
bool send(const CAutoMem &data);
//设置 socket 阻塞和非阻塞
bool setblocking(bool op);
//检测 http 数据包是否完整
bool checkhttppacket(const char* buffer);
public:
//默认最小超时基数100毫秒
CMyHttp(const std::string& srvip ,int port,
int timeoutmillisecond = 1500,
int maxretrycount = 4);
~CMyHttp();
//得到发送的请求
const std::string GetReq();
//建立连接
int connect();
int sendget(const std::string &url,
const std::map<std::string,std::string> &values,
bool URLENCODING = true);
int sendpost(const std::string &url,
const std::map<std::string,std::string> &values,
bool URLENCODING = true);
int sendpost(const std::string &url,const std::string &values);
int sendpostxml(const std::string &url,
const std::map<std::string,std::string> &values,
bool URLENCODING = true);
int sendpostxml(const std::string &url,const std::string &xml);
//接收数据
int receive(char *buff,int bufflen);
};
class CDNS
{
private:
const std::string checkhost(const std::string &host);
public:
void parsehost(const std::string &host,std::vector<std::string> &addrs);
void parsedomain(const std::string &host,std::vector<std::string> &addrs);
};
#endif
/*****************************************************************/
//name : myhttp.cpp
//function : http 请求
//author : mark
//date : 2008-05-13
//modifier : 2009-08-17,使用非阻塞socket,结合select
//去判断数据发送和接收情况,默认最坏情况,从连接发起到发送接收完
//成数据,都失败4次,耗时最大浪费接近 3 秒,其中发送1000 毫
//秒,连接和接收各1000毫秒。实际每次操作的最大耗时是C:
//设定A=(sum(1~(MAXIMUMERRORNUMBER - 1)) *1000) 毫秒,如果A大于
//timeoutmillisecond,则相应MAXIMUMERRORNUMBER缩小,直到符合
//A小于timeoutmillisecond;
//设定B=(timeoutmillisecond + MAXIMUMERRORNUMBER * 100) 毫秒,
//则最大耗时基本上小于B;最终是:A<C<B
/***********************************************************************/
#include "myhttp.h"
#include "automem.h"
#include "urlcode.h"
#include "func_utility.h"
#include "datetime.h"
#include <map>
#include <vector>
using namespace std;
#ifdef WIN32
#include "WINSOCK2.H"
#include <io.h>
#include "ws2tcpip.h"
/*
class CWSADATA
{
public:
CWSADATA()
{
WSADATA wsaData;
WSAStartup(0x101,&wsaData);
}
WSADATA()
{
WSACleanup();
}
};
CWSADATA instance;
*/
#else
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <time.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <netdb.h>
//#include <sys/select.h>
#endif
CMyHttp::CMyHttp(const std::string& srvip ,int port,int timeoutmillisecond,
int maxretrycount)
:m_fd(MY_INVALID_SOCKET),
m_timeoutmillisecond(timeoutmillisecond),
m_basicmicrosecond(100000),
MAXIMUMERRORNUMBER(maxretrycount),
m_srvip(srvip),
m_srvport(port)
{
if(this->m_timeoutmillisecond > 5000 || this->m_timeoutmillisecond < 1000)
{
m_timeoutmillisecond = 1500;
}
}
CMyHttp::~CMyHttp(void)
{
release();
}
void CMyHttp::release()
{
if(m_fd != MY_INVALID_SOCKET)
{
closesock(m_fd);
m_fd = MY_INVALID_SOCKET;
}
}
int CMyHttp::closesock(mysocket connectsocket)
{
#ifdef WIN32
return ::closesocket(connectsocket);
#else
return ::close(connectsocket);
#endif
}
//设置 socket 阻塞和非阻塞
bool CMyHttp::setblocking(bool op)
{
unsigned long result = 0;
#ifdef WIN32
if(op)
{
result = 0;
}
else
{
result = 1;
}
result = ::ioctlsocket(m_fd,FIONBIO,&result);
#else
int fl = 0;
if ((fl = fcntl(m_fd,F_GETFL,0)) == -1)
{
return false;
}
if(op)
{
fl &= ~O_NONBLOCK;
}
else
{
fl |= O_NONBLOCK;
}
if (fcntl(m_fd,F_SETFL,fl) == -1)
{
result = 1;
}
#endif
return result == 0?true:false;
}
//支持指数回退,重新连接
int CMyHttp::connect()
{
int times = 1;
int result = MY_INVALID_SOCKET;
CDateTime start;
//printf("%d,%s/n",times,dt.LongDateTimeWithMilliSec().c_str());
while(result != 0 && times <= MAXIMUMERRORNUMBER)
{
release();
//操作最大时间
CDateTime now;
if(now.SubMilliSecond(start) >= m_timeoutmillisecond)
{
break;
}
m_fd = socket(AF_INET,SOCK_STREAM,0);
if(!this->setblocking(false))
{
times++;
result = MYERRNO;
continue;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(m_srvip.c_str());
addr.sin_port = htons(m_srvport);
result = ::connect(m_fd,(struct sockaddr*)&addr,sizeof(addr));
if (result == 0)
{
//连接成功
return result;
}
result = MYERRNO;
//开始用 select 去判断指定socket是否连接成功
fd_set writeset,exceptset;
FD_ZERO(&writeset);
FD_SET(m_fd,&writeset);
FD_ZERO(&exceptset);
FD_SET(m_fd,&exceptset);
struct timeval timeout = {0,0};
timeout.tv_sec = 0;
timeout.tv_usec = this->m_basicmicrosecond * times;
#ifdef WIN32
if (result != WSAEWOULDBLOCK)
{
times++;
continue;
}
do
{
result = select(0,0,&writeset,&exceptset,&timeout);
}while(result < 0 && MYERRNO == EINTR);
#else
if (result != EINPROGRESS)
{
times++;
continue;
}
do
{
result = select(m_fd + 1,0,&writeset,&exceptset,&timeout);
}while(result < 0 && MYERRNO == EINTR);
#endif
if(result == MY_SOCKET_ERROR)
{
//发生错误
result = MYERRNO;
times++;
continue;
}
else if(result == 0)
{
//超时发生,放弃连接
result = MY_SOCKET_ERROR;
times++;
continue;
}
if(FD_ISSET(m_fd,&writeset))
{
//完成连接
result = 0;
#ifdef WIN32
//
#else
socklen_t len = sizeof(result);
result = getsockopt(m_fd,SOL_SOCKET,SO_ERROR,(char*)&result,&len);
#endif
}
else
{
//超时发生,放弃连接
result = MY_SOCKET_ERROR;
}
times++;
}
//CDateTime dt1;
//printf("%d,%s/n",times,dt1.LongDateTimeWithMilliSec().c_str());
return result;
}
bool CMyHttp::send(const CAutoMem &data)
{
int total_len = (int)data.Length();
int sendlen = 0;
int times = 1;
CDateTime start;
//printf("%d,%s/n",times,dt.LongDateTimeWithMilliSec().c_str());
while(sendlen < total_len
&& times <= MAXIMUMERRORNUMBER)
{
//操作最大时间
CDateTime now;
if(now.SubMilliSecond(start) >= m_timeoutmillisecond)
{
break;
}
int newsend = ::send(m_fd,data.Get() + sendlen ,total_len - sendlen,0);
if(newsend == MY_SOCKET_ERROR && MYERRNO != EAGAIN)
{
return false;
}
sendlen += (newsend>0?newsend:0);
//使用select 去判断是否数据可以继续发
fd_set writeset,exceptset;
FD_ZERO(&writeset);
FD_SET(m_fd,&writeset);
FD_ZERO(&exceptset);
FD_SET(m_fd,&exceptset);
struct timeval timeout = {0,0};
timeout.tv_sec = 0;
timeout.tv_usec = m_basicmicrosecond * times;
int result = 0;
#ifdef WIN32
do
{
result = select(0,0,&writeset,&exceptset,&timeout);
}while(result < 0 && MYERRNO == EINTR);
#else
do
{
result = select(m_fd + 1,0,&writeset,&exceptset,&timeout);
}while(result < 0 && MYERRNO == EINTR);
#endif
if(FD_ISSET(m_fd,&exceptset))
{
break;
}
//printf("%d/n",result);
//内核缓冲区间有空间,数据可以继续发送
if(FD_ISSET(m_fd,&writeset))
{
//
}
//发送无效果,算超时一次,算一次失败
if(newsend <= 0)
{
times++;
}
}
if(sendlen != total_len)
{
return false;
}
return true;
}
//接收数据,使用 http协议,尽量一次收取全部数据
int CMyHttp::receive(char *buff,int bufflen)
{
if(buff == 0 || bufflen <= 0)
{
return 0;
}
//必须是1,否则select 会被至少执行两次,最后一次必须超时才能返回
//如果要可配置,必须指定协议解析模块,能判断数据接收完毕后退出
//一般情况下,使用http 1.0 协议,指定 connection :close ,
//TCP 连接会进入同时关闭的情况,这样双方都不太消耗网络资源
int received = 0;
int times = 1;
CDateTime start;
//printf("%d,%s/n",times,start.LongDateTimeWithMilliSec().c_str());
while(received < bufflen
&& times <= MAXIMUMERRORNUMBER)
{
//操作最大时间
CDateTime now;
if(now.SubMilliSecond(start) >= m_timeoutmillisecond)
{
break;
}
//开始用 select 去判断指定socket是否可以有数据读
fd_set readset,exceptset;
FD_ZERO(&readset);
FD_SET(m_fd,&readset);
FD_ZERO(&exceptset);
FD_SET(m_fd,&exceptset);
struct timeval timeout = {0,0};
timeout.tv_sec = 0;
timeout.tv_usec = this->m_basicmicrosecond * times;
int result = 0;
#ifdef WIN32
do
{
result = ::select(0,&readset,0,&exceptset,&timeout);
}while(result < 0 && MYERRNO == EINTR);
#else
do
{
result = ::select(m_fd + 1,&readset,0,&exceptset,&timeout);
}while(result < 0 && MYERRNO == EINTR);
#endif
if(FD_ISSET(m_fd,&exceptset))
{
break;
}
//CDateTime dt1;
//printf("vvvvv=%d,%s/n",times,dt1.LongDateTimeWithMilliSec().c_str());
//printf("receive=%d/n",result);
//有数据可以读取
if(FD_ISSET(m_fd,&readset))
{
#ifdef WIN32
int newrecv = ::recv(m_fd,buff + received,bufflen - received,0);
#else
int newrecv = ::recv(m_fd,buff + received,bufflen - received,MSG_WAITALL);
#endif
//printf("vv=%d,%d/n",newrecv,received);
if(newrecv == MY_SOCKET_ERROR)
{
int err = MYERRNO;
#ifdef WIN32
if(err != EAGAIN && err != WSAEWOULDBLOCK)
{
break;
}
#else
if(err != EAGAIN && err != EWOULDBLOCK)
{
break;
}
#endif
}
else if(newrecv == 0)
{
//连接被关闭
break;
}
else if(newrecv > 0)
{
//printf("aa=%d,%d/n",newrecv,received);
received += newrecv;
//数据包已经完整(这个方法是很不保险,如果数
//据报过大,http 头完整后,但是http数据部分却可能接收不完整,比如resin3.2)
//比较好的办法还是要通过socket 来判断数据是否接收完全
if(this->checkhttppacket(buff))
{
break;
}
//不管收到了多少数据,算正常
continue;
}
else
{
//
}
}
else
{
//算超时一次
times++;
}
}
//CDateTime dt1;
//printf("%d,%d,%s/n",times,received,dt1.LongDateTimeWithMilliSec().c_str());
return received;
}
//初步检测 http 数据包是否完整
bool CMyHttp::checkhttppacket(const char* buffer)
{
const char * HTTP_HEAD_TAG = "/r/n/r/n";
const char * HTTP_LINE_TAG = "/r/n";
//const int HTTP_LINE_TAG_LEN = 2;
//const int HTTP_HEAD_TAG_LEN = 4;
char* p = strstr(buffer, HTTP_HEAD_TAG);
if(0 != p)
{
//_nHeaderLen = p - buffer + HTTP_HEAD_TAG_LEN;
return true;
}
p = strstr(buffer, HTTP_LINE_TAG);
if(0 != p && p == buffer)
{
//_nHeaderLen = HTTP_LINE_TAG_LEN;
return true;
}
return false;
}
int CMyHttp::sendpostxml(const std::string &url,
const std::map<std::string,std::string> &values,
bool URLENCODING)
{
int result = 1;
const std::string STR = "http://";
size_t pos = url.find(STR);
if(pos == std::string::npos || url.length() <= 5)
{
return -1;
}
size_t posmid = url.find("/",pos + STR.length());
if(posmid == std::string::npos)
{
return -1;
}
std::string host = "";
host = url.substr(pos + STR.length(),posmid - pos - STR.length());
std::map<std::string,std::string>::const_iterator it;
std::string req = "<?xml version=/"1.0/" encoding=/"gb2312/"?>";
req += "<message>";
for(it = values.begin();it != values.end();++it)
{
if(URLENCODING)
{
CUrlCode urlcode;
req += urlcode.encode(it->first);
req += "=";
req += urlcode.encode(it->second);
}
else
{
req += "<";
req += it->first;
req += ">";
req += it->second;
req += "</";
req += it->first;
req += ">";
}
}
req += "</message>";
std::string path = "";
//path = "POST " + url + " HTTP/1.1/r/n";
path = "POST " + url + " HTTP/1.0/r/n";
path += "Accept: */*/r/n";
path += "Accept-Language: zh-cn/r/n";
path += "Accept-Encoding: gzip,default/r/n";
path += "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; ";
path += "Windows NT 5.1; SV1; TencentTraveler 4.0; .NET CLR 1.1.4322)/r/n";
path += "Host: " + (host.length() > 0?host:m_srvip);
req += ":" + util.stream_cast<std::string>(m_srvport);
req += "/r/n";
path += "Content-Length:";
char buff[20] = {0};
sprintf(buff,"%u/r/n",req.length());
path += buff;
//path += "Transfer-Encoding: chunked/r/n";
path += "Connection: close/r/n";
path += "Content-Type: application/x-www-form-urlencoded/r/n/r/n";
req = path + req;
m_req = req;
CAutoMem mem((int)req.length());
memcpy(mem.Get(),req.c_str(),req.length());
if(!this->send(mem))
{
result = -1;
}
return result;
}
int CMyHttp::sendpostxml(const std::string &url,const std::string &xml)
{
int result = 1;
const std::string STR = "http://";
size_t pos = url.find(STR);
if(pos == std::string::npos || url.length() <= 5)
{
return -1;
}
size_t posmid = url.find("/",pos + STR.length());
if(posmid == std::string::npos)
{
return -1;
}
std::string host = "";
host = url.substr(pos + STR.length(),posmid - pos - STR.length());
std::string path = "";
//path = "POST " + url + " HTTP/1.1/r/n";
path = "POST " + url + " HTTP/1.0/r/n";
path += "Accept: */*/r/n";
path += "Accept-Language: zh-cn/r/n";
path += "Accept-Encoding: gzip,default/r/n";
path += "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; ";
path += "Windows NT 5.1; SV1; TencentTraveler 4.0; .NET CLR 1.1.4322)/r/n";
path += "Host: " + (host.length() > 0?host:m_srvip);
req += ":" + util.stream_cast<std::string>(m_srvport);
req += "/r/n";
path += "Content-Length:";
char buff[20] = {0};
sprintf(buff,"%u/r/n",xml.length());
path += buff;
//path += "Transfer-Encoding: chunked/r/n";
path += "Connection: close/r/n";
path += "Content-Type: text/xml/r/n/r/n";
m_req = path + xml;
CAutoMem mem((int)m_req.length());
memcpy(mem.Get(),m_req.c_str(),m_req.length());
if(!this->send(mem))
{
result = -1;
}
return result;
}
int CMyHttp::sendpost(const std::string &url,
const std::map<std::string,std::string> &values,
bool URLENCODING)
{
int result = 1;
const std::string STR = "http://";
size_t pos = url.find(STR);
if(pos == std::string::npos || url.length() <= 5)
{
return -1;
}
size_t posmid = url.find("/",pos + STR.length());
if(posmid == std::string::npos)
{
return -1;
}
std::string host = "";
host = url.substr(pos + STR.length(),posmid - pos - STR.length());
std::map<std::string,std::string>::const_iterator it;
std::string req = "";
for(it = values.begin();it != values.end();++it)
{
if(URLENCODING)
{
CUrlCode urlcode;
req += urlcode.encode(it->first);
req += "=";
req += urlcode.encode(it->second);
}
else
{
req += it->first;
req += "=";
req += it->second;
}
req += "&";
}
if(req.length() > 0 && req[req.length() - 1] == '&')
{
req = req.substr(0,req.length() - 1);
}
std::string path = "";
//path = "POST " + url + " HTTP/1.1/r/n";
path = "POST " + url + " HTTP/1.0/r/n";
path += "Accept: */*/r/n";
path += "Accept-Language: zh-cn/r/n";
path += "Accept-Encoding: gzip,default/r/n";
path += "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; ";
path += "Windows NT 5.1; SV1; TencentTraveler 4.0; .NET CLR 1.1.4322)/r/n";
path += "Host: " + (host.length() > 0?host:m_srvip);
req += ":" + util.stream_cast<std::string>(m_srvport);
req += "/r/n";
path += "Content-Length:";
char buff[20] = {0};
sprintf(buff,"%u/r/n",req.length());
path += buff;
//path += "Transfer-Encoding: chunked/r/n";
path += "Connection: close/r/n";
path += "Content-Type: application/x-www-form-urlencoded/r/n/r/n";
req = path + req;
m_req = req;
CAutoMem mem((int)req.length());
memcpy(mem.Get(),req.c_str(),req.length());
if(!this->send(mem))
{
result = -1;
}
return result;
}
int CMyHttp::sendpost(const std::string &url,
const std::string &values)
{
int result = 1;
std::string path = "";
//path = "POST " + url + " HTTP/1.1/r/n";
path = "POST " + url + " HTTP/1.0/r/n";
path += "Accept: */*/r/n";
path += "Accept-Language: zh-cn/r/n";
path += "Accept-Encoding: gzip,default/r/n";
path += "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; ";
path += "Windows NT 5.1; SV1; TencentTraveler 4.0; .NET CLR 1.1.4322)/r/n";
//path += "Host: " + "/r/n";
path += "Content-Length:";
char buff[20] = {0};
sprintf(buff,"%u/r/n",values.length());
path += buff;
//path += "Transfer-Encoding: chunked/r/n";
path += "Connection: close/r/n";
path += "Content-Type: application/x-www-form-urlencoded/r/n/r/n";
path = path + values;
m_req = path;
CAutoMem mem((int)path.length());
memcpy(mem.Get(),path.c_str(),path.length());
if(!this->send(mem))
{
result = -1;
}
return result;
}
int CMyHttp::sendget(const std::string &url,
const std::map<std::string,std::string> &values,
bool URLENCODING)
{
int result = 1;
std::map<std::string,std::string>::const_iterator it;
std::string req = "";
for(it = values.begin();it != values.end();++it)
{
if(URLENCODING)
{
CUrlCode urlcode;
req += urlcode.encode(it->first);
req += "=";
req += urlcode.encode(it->second);
}
else
{
req += it->first;
req += "=";
req += it->second;
}
req += "&";
}
if(req.length() > 0 && req[req.length() - 1] == '&')
{
req = req.substr(0,req.length() - 1);
}
std::string uri = url;
const std::string HTTP = "http://";
MyString str;
std::string host = "";
if(str.strncasecmp(HTTP.c_str(),uri.c_str(),HTTP.length()) == 0)
{
size_t pos = uri.find("/", HTTP.length());
if(pos != std::string::npos)
{
host = uri.substr(HTTP.length(),pos - HTTP.length());
uri = uri.substr(pos);
}
}
req = "GET " + uri + "?" + req;
//req += " HTTP/1.1/r/n";
req += " HTTP/1.0/r/n";
req += "Accept: */*/r/n";
req += "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0;";
req += "Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1)/r/n";
req += "Host: ";
CFunc_Util util;
req += host.length() > 0?host:m_srvip;
req += ":" + util.stream_cast<std::string>(m_srvport);
req += "/r/n";
req += "Connection: close/r/n";
req += "/r/n";
m_req = req;
CAutoMem mem((int)req.length());
memcpy(mem.Get(),req.c_str(),req.length());
if(!this->send(mem))
{
result = -1;
}
return result;
}
const std::string CMyHttp::GetReq()
{
return m_req;
}
void CDNS::parsehost(const std::string &host,std::vector<string> &addrs)
{
std::string localhost = this->checkhost(host);
//直接就是合法的 ip 地址
if(inet_addr(localhost.c_str()) != INADDR_NONE)
{
addrs.push_back(localhost);
return;
}
struct hostent *hptr = 0;
#ifdef WIN32
if((hptr = gethostbyname(localhost.c_str())) == 0)
{
return ;
/* 如果调用gethostbyname发生错误,返回1 */
}
#else
int rc = 0;
char buff[4096] = {0};
struct hostent *result = 0;
struct hostent myhostent;
if(gethostbyname_r(localhost.c_str(),&myhostent,buff,sizeof(buff),&result,&rc) != 0)
{
return;
}
hptr = &myhostent;
#endif
/* 将主机的规范名打出来 */
//printf("official hostname:%s/n",hptr->h_name);
/* 主机可能有多个别名,将所有别名分别打出来 */
//for(pptr = hptr->h_aliases; *pptr != NULL; pptr++)
// printf(" alias:%s/n",*pptr);
/* 根据地址类型,将地址打出来 */
switch(hptr->h_addrtype)
{
case AF_INET:
case AF_INET6:
{
/* 将刚才得到的所有地址都打出来。其中调用了inet_ntop()函数 */
for(char **pptr = hptr->h_addr_list;*pptr != 0;pptr++)
{
#ifdef WIN32
addrs.push_back(inet_ntoa(*((in_addr*)*pptr)));
#else
char str[128] = {0};
inet_ntop(hptr->h_addrtype,*pptr,str,sizeof(str));
addrs.push_back(str);
#endif
}
break;
}
default:
{
break;
}
}
}
const std::string CDNS::checkhost(const std::string &host)
{
/* 调用gethostbyname()。调用结果都存在hptr中 */
const std::string HTTP = "http://";
const std::string HTTPS = "https://";
std::string localhost = host;
MyString mystr;
if(mystr.strncasecmp(host.c_str(),HTTP.c_str(),HTTP.length()) == 0)
{
localhost = host.substr(HTTP.length());
}
if(mystr.strncasecmp(host.c_str(),HTTPS.c_str(),HTTPS.length()) == 0)
{
localhost = host.substr(HTTPS.length());
}
return localhost;
}
void CDNS::parsedomain(const std::string &host,std::vector<string> &addrs)
{
std::string localhost = this->checkhost(host);
//直接就是合法的 ip 地址
if(inet_addr(localhost.c_str()) != INADDR_NONE)
{
addrs.push_back(localhost);
return;
}
struct addrinfo hints;
struct addrinfo *res = 0;
memset(&hints,0,sizeof(struct addrinfo));
hints.ai_addr = 0;
hints.ai_addrlen = 0;
hints.ai_canonname = 0;
//hints.ai_family = AF_INET|AF_INET6;
hints.ai_family = AF_INET;
//hints.ai_flags = AI_NUMERICHOST|AI_CANNONAME;
hints.ai_flags = AI_CANONNAME;
hints.ai_next = 0;
//hints.ai_protocol = IPPROTO_IP|IPPROTO_IPV4|IPPROTO_IPV6|IPPROTO_UDP|IPPROTO_TCP;
hints.ai_protocol = IPPROTO_IP;
//hints.ai_socktype = SOCK_STREAM|SOCK_DGRAM;
hints.ai_socktype = SOCK_STREAM;
int ret = 0;
ret = getaddrinfo(localhost.c_str(),0,&hints,&res);
if(ret != 0)
{
freeaddrinfo(res);
return ;
}
struct addrinfo *ptr = res;
while(ptr != 0)
{
//解析所要的域名信息
struct sockaddr_in * in = (struct sockaddr_in *)ptr->ai_addr;
#ifdef WIN32
addrs.push_back(inet_ntoa(in->sin_addr));
#else
char str[128] = {0};
inet_ntop(in->sin_family,&in->sin_addr,str,sizeof(str));
addrs.push_back(str);
#endif
ptr = ptr->ai_next;
}
freeaddrinfo(res);
}