一个比较好用的socket 类封装(封装http 请求)

2023-05-16

 


/*****************************************************************/
//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);
}

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一个比较好用的socket 类封装(封装http 请求) 的相关文章

  • 单片机编程用什么软件?单片机开发软件有哪些?华维告诉你.

    大家好 xff0c 我是华维 最近有小伙伴问我单片机编程用哪些软件 xff0c 结合我工作10年单片机经验 xff0c 在此回答一下大家的问题 单片机编程软件有很多 xff0c 什么protues仿真 Labview Pycharm等等 x
  • stm32单片机学习秘籍(完整版)

    大家好 xff0c 我是华维麦琪 xff0c 今天来分享下我们华维团队十年经验总结 xff0c 如何能快速学好stm32单片机 xff01 最近看到很多小伙伴学STM32学的一脸懵逼 xff0c 有些甚至学1年都不会 xff0c 有些虽然学
  • 深度解析,单片机运行原理,你知道吗?

    同名回复 入门资料 获取单片机入门到高级进阶教程 单片机是将中央处理单元 xff08 CPU xff09 储存器 输入输出集成在一片芯片上 xff0c 可以说单片机就是一台微型计算机 xff0c 只是和我们平常使用的计算机相比它的功能有所不
  • 玩单片机需要学数电、模电吗?

    首先我们来了解下什么是模电和数电 模拟电路 xff1a 模拟电路是指用来对模拟信号进行传输 变换 处理 放大 测量和显示等工作的电路 模拟信号是指连续变化的电信号 模拟电路是电子电路的基础 xff0c 它主要包括放大电路 信号运算和处理电路
  • 2022年入坑,互联网开发和嵌入式开发,你会选择哪个?

    前言 2022年入坑 xff0c 互联网开发和嵌入式开发 xff0c 你会选择哪个 xff1f 我想很多人会毫不犹豫的选择互联网吧 xff0c 嵌入式没有那么大众化 xff0c 没有那么多关注 xff0c 对它的概念可能没有那么清楚 今天跟
  • 入门必看,51单片机学习三步走

    回想起我初学单片机到现在已经有六年了 学习期间使用了51单片机 XX卡尔单片机 STM16 STM32等单片机 每次接触新的单片机我首先会熟悉它的基本开发 xff0c 然后再通过项目的实现去深入的了解它 大家都知道51单片机是最容易学习的
  • 【华维教学】用STM32Cube和Keil5点亮一个LED

    大家好 xff0c 我是华维 今天我们讲下用STM32CubeMX和Keil5点亮一个LED xff0c 这个项目比较简单 xff0c 大家都可以尝试下 这个就是我们今天的主角 xff0c 这款单片机芯片是STM32F030K6T6 这个开
  • 浅谈ESP8266、ESP32和STM32的区别

    大家好 xff0c 我是华维蔵鹰 xff0c 关注我可以学习更多的单片机知识 今天我们来聊聊ESP8266 ESP32和STM32 乐鑫聚布局联网领域已经有些年头了 xff0c 先是推出了ESP8266这样的低价带有wifi的芯片 xff0
  • 物联网专业未来没有前途了吗?

    大家好 xff0c 我是华维蔵鹰 xff0c 想学习单片机的同学可以关注 私信我 最近在知乎看到一个同学对物联网的前景感觉到迷茫 xff0c 原因是因为某大学的教授去他们那里讲座 xff0c 然后说他们的学校物联网的专业已经没有招新了 xf
  • 面向单片机编程(一)- 单片机该怎么学

    面向单片机编程 xff08 一 xff09 单片机该怎么学 标签 单片机 C51 单片机该怎么学 xff1f 应该从哪里入手 xff1f 要怎么使用单片机实现一个小 xff08 大 xff09 目标 xff1f 下面我也来和大家一起分享一下
  • JAVA中String的底层解析

    JAVA中String 是Final类不能被继承 JAVA 对String的处理和一般Class有所不同 这文章主要是解释一下String的存储模式和java的字符串常量池的机制 xff0c 和几个涉及底层的引用问题解析 首先提出几个问题
  • 面向单片机编程(二)-开端,点亮第一个LED

    上一章中我们已经认识了单片机 xff0c 并且完成了开发环境的搭建 xff0c 这章中我们正式开始进入单片机编程的学习 xff0c 本章的学习目标是点亮一盏LED灯 一 创建一个Keil工程 1 双击运行Keil uVision5 xff0
  • ROS2——创建ROS2工作空间

    ROS2中的工作空间类似我们常说的概念 工程 xff0c 是我们在ROS中开发具体项目的空间 xff0c 所有功能包的源码 配置 编译都在该空间下完成 我们可能会同时开发多个项目 xff0c 就会产生多个工作空间 xff0c 所以工作空间之
  • C++ Primer (暂时完结)

    C 43 43 Primer C 43 43 预备知识泛型编程第二章 开始学习C 43 43 2 1 3 C 43 43 预处理器 和iostream 文件名称空间第二章 输出输入endl控制符换行符规范的书写格式c 43 43 源码风格
  • Futaba S-BUS controlled by mbed(使用mbed控制Futaba S-BUS)

    原文地址 xff1a Futaba S BUS controlled by mbed 代码地址 xff1a SBUS Library Introduction xff08 简介 xff09 The Futaba S BUS protocol
  • STorM32 BGC 相关

    下载 storm32 bgc v130电路图 xff08 http download csdn net detail hxiaohai 9901379 xff09 drv8313器件手册 xff08 http download csdn n
  • TMC5160步进电机驱动芯片开发手记

    2018年 xff0c Trinamic推出了新的型号TMC5160 xff0c 自带6点速度曲线 StealthChop和SpreadCycle静音防抖技术等很不错的功能 xff0c 目前使用官方BOB板进行开发测试 xff0c 在初步参
  • 导航过程各坐标系之间转换

    做导航最烦人的就是坐标系之间的转换 xff0c 每次都要去推相应的公式 xff0c 所以特地写点干货 xff0c 解决你坐标系转换问题 1 经纬高转地心 xff08 1 xff09 式1中 xff0c 为纬度 xff0c 为经度 xff0c
  • requestAuthentication详解

    欢迎关注我的公众号 xff1a 目前刚开始写一个月 xff0c 一共写了18篇原创文章 xff0c 文章目录如下 xff1a istio多集群探秘 xff0c 部署了50次多集群后我得出的结论 istio多集群链路追踪 xff0c 附实操视
  • 运行SLAM遇到的问题

    运行的代码来自与高翔的博客 1 绝对路径 将程序中的相对路径改成绝对路径 xff0c 否则找不到图片 2 pcl问题 在CMakeLists中要加上一行代码 list REMOVE ITEM PCL LIBRARIES 34 vtkproj

随机推荐

  • python tcping(ping命令)

    python tcping xff08 ping命令 使用tcping库中的ping方法使用如下 xff1a span class token keyword from span tcping span class token keywor
  • RecycledViewPool的使用和堆内存分析

    RecycledViewPool在 ViewPager 43 RecyclerView的场景下可以大放光彩 下面就来验证一下它的优点 xff1a 首先我们自定定义一个View放在ViewHolder中 xff1a public class
  • SX1261/2芯片开发那些事儿(一)时钟源选择

    相信大家第一次接触LoRa芯片时 阅读Semtech官方Demo代码或者自己进行项目开发时 xff0c 不知道对于待机模式 xff0c 是使用STDBY RC还是STDBY XOSC呢 xff1f 今天我们就来介绍射频芯片SX1261 2该
  • 解决Ubuntu20.04安装ROS过程镜像源问题

    解决Ubuntu20 04安装ROS过程镜像源问题 问题背景问题描述解决方案参考链接 问题背景 我是先安装了 Windows10 子系统 WSL wsl install 并安装Ubuntu20 04 wsl install d Ubuntu
  • 解决 qt.qpa.xcb: could not connect to display 问题

    2022 07 21更新 现在WSL2已经可以直接运行 Linux GUI 了 xff01 xff01 xff01 不再需要安装Xserver xff08 XLaunch xff09 之类的 xff01 xff01 xff01 参考微软的官
  • 解决在VScode中调试C++代码断点无效、断点错位的问题

    问题背景 最近在学习高翔博士的经典教程 视觉SLAM十四讲 xff08 第2版 xff09 xff0c 使用其配套的Github中C 43 43 代码进行学习 xff0c 在调试时发现断点无效 错位的问题 xff0c 查阅了一些资料 xff
  • Ubuntu系统安装在移动固态硬盘,实现在不同电脑即插即用

    Ubuntu系统安装在移动固态硬盘 xff0c 实现在不同电脑即插即用 一 前期准备二 制作系统启动盘2 1 Ubuntu20 04系统下载2 2 制作U盘启动盘 三 磁盘分区 xff08 重点 xff09 四 Ubuntu系统安装 xff
  • 详解C/C++代码的预处理、编译、汇编、链接全过程

    1 C C 43 43 运行的四个步骤 编写完成一个C C 43 43 程序后 xff0c 想要运行起来 xff0c 必须要经过四个步骤 xff1a 预处理 编译 汇编和链接 每个步骤都会生成对应的文件 xff0c 如下图所示 xff08
  • VSCode调试C++代码的多种方案

    以下内容均针对 Linux 操作系统 xff08 包括Windows的Linux子系统WSL2 xff09 本文是对Linux系统中使用VSCode编译调试C 43 43 代码的系列文章的总结 xff0c 前面三篇文章如下 xff1a 详解
  • 【ROS】rostopic常用命令

    记录ROS查看话题的常用命令 xff1a rostopic 查看节点列表 xff1a rostopic list 查看节点信息 xff0c 如相机节点的内参K矩阵 畸变D矩阵 分辨率等等 rostopic echo camera camer
  • 【ROS笔记】设置、修改ROS环境变量

    ROS设置环境变量 ROS安装到Ubuntu后 xff0c 默认在 opt路径下 xff0c 由于在使用过程中需要频繁在终端使用ROS命令 xff0c 需要对其环境变量进行设置 Ubuntu默认使用终端为bash xff0c 在bash中设
  • 【ROS笔记】工作空间(workspace)、功能包(package)的介绍及创建

    初接触ROS时 xff0c 对其文件结构容易产生困惑和混淆 xff0c 比如 catkin ws到底是什么 xff1f catkin ws src目录下存放的是什么 xff1f catkin ws src路径下怎么还会有其他的src 目录
  • RecyclerView中倒计时item的优雅方案

    本文介绍在RecyclerView中使用倒计时楼层 xff0c 并且每秒刷新显示倒计时 没有纠结于样式 xff0c 主要介绍代码结构和设计模式 先看一下效果 xff1a 我们采取的是观察者模式的方法 xff0c 启动一个handler xf
  • bluerov

    ov这个东西其实不难 xff0c 比较麻烦的是密封 xff0c 防水等工作 xff0c 而非一些技术性工作 xff08 所谓技术性工作就是算法 xff0c 人工智能等 xff09 现在供玩家玩的Rov xff0c 基本模式是这样的 xff0
  • 在线教程 | 用「网红项目」DeepSOCIAL 进行社交距离监测

    首发自 xff1a 公众号 HyperAI超神经 内容一览 xff1a YOLO v4 是一个实时的 高精度的目标检测模型 xff0c 本教程将详细讲解如何基于 YOLO v4 和 SORT 算法 xff0c 实现在多目标条件下的人群距离检
  • C#实现服务端/客户端的tcp异步通信完整示例

    demo 通过一个简单的demo xff0c 实现服务器和客户端之间的tcp异步通信 消息进行了Des加密和解密 运行动图如下 xff1a 图中有三个程序在运行 xff0c 最左边是服务端 xff0c 另外两个是客户端 xff0c 客户端可
  • C++封装HTTP

    C 43 43 封装HTTP Client 简介HTTP请求头封装HTTP请求头基本格式post请求头封装post请求头 HTTP Client 以及HTTP Server交互HTTP消息解析TCP封装HTTP Client的坑 Trans
  • android 自定义多功能进度条

    自定义进度条 xff0c 直接在布局文件里传入颜色值 xff0c 不用自己再去写样式 xff0c 还可以 效果图 xff1a git地址
  • 树莓派L298N电机驱动程序连接图文教程

    手里有一块树莓派3闲置很久 xff0c 不知干点啥好呢 看到不少网友用树莓派做智能小车 xff0c 好像很好玩的酱紫 xff0c 就到淘宝买了一些配件 对于硬件小白的我来说安装过程并不轻松 xff0c 网上看了很多资料但有的地方介绍的并不很
  • 一个比较好用的socket 类封装(封装http 请求)

    name myhttp h function http 请求 copyright author mark date 2008 05 13 ifndef MY HTTP INCLUDE define MY HTTP INCLUDE inclu