muduo原始碼解析20-inetaddress類
阿新 • • 發佈:2020-08-28
inetaddress類:
說明:
封裝了一個套接字地址類,實現與IPV6和IPV4具體操作無關的一個類,使用者只需要在定義時確定IPV4/IPV6即可,所提供的操作與具體的IPV4/IPV6協議無關。
內部用共同體union {sockaddr_in6 m_addr6 ; sockaddr_in m_addr}實現,因此sizeof(inetaddress)==sizeof(sockaddr_in6)
建構函式要求指定建立的是IPV6還是IPV4地址,用來確定使用m_addr6還是m_addr
建構函式意義就是為了實現內部m_addr的初始化,也就是設定三個成員port,addr和family
內部還提供了一些get IP,port,family,sockaddr*等一些函式用於獲取資訊
成員變數:
private: union { //size分別是多少,待會測一下 //sockaddr:16,sockaddr_in:16,sockaddr_in6:28 struct sockaddr_in m_addr; struct sockaddr_in6 m_addr6; };
成員函式:
public: //所有的建構函式都完成m_addr6/m_addr的初始化,也就是設定port,addr,family //explicit禁止隱式型別轉換explicit inetaddress(uint16_t port=0,bool loopbackOnly=false,bool ipv6=false); inetaddress(string ip,uint16_t port,bool ipv6=false); //建構函式,IPV4地址 explicit inetaddress(const struct sockaddr_in& addr) :m_addr(addr) {} //建構函式,IPV6地址 explicit inetaddress(const structsockaddr_in6& addr) :m_addr6(addr) {} //返回地址族,IP,IP:port,port,sockaddr*資訊 sa_family_t family() const {return m_addr.sin_family;} string toIp() const; string toIpPort() const; uint16_t toPort() const; const struct sockaddr* getSockAddr() const { return sockets::sockaddr_cast(&m_addr6); } //設定IPV6 m_addr void setSockAddrInet6(const struct sockaddr_in6& addr6) { m_addr6=addr6; } //獲取m_addr.sin_addr.s_addr,即IP地址網路位元組序 uint32_t ipNetEndian() const; //獲取埠號的網路位元組序 uint16_t portEntEndian() const{return m_addr.sin_port;} //執行緒安全,完成主機名到IP地址的轉換,不改變埠號和地址族 //內部使用gethostbyname_r()實現 static bool resolve(string hostname,inetaddress* result); //設定 IPV6 ScopeId void setScopeId(uint32_t scope_id);
inet_address.h:
#ifndef INETADDRESS_H #define INETADDRESS_H #include"base/copyable.h" #include<netinet/in.h> #include"base/types.h" namespace mymuduo { namespace net { //宣告sockets::sockaddr_cast函式 namespace sockets{ const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); }//namespace sockets class inetaddress:copyable { public: //所有的建構函式都完成m_addr6/m_addr的初始化,也就是設定port,addr,family //explicit禁止隱式型別轉換 explicit inetaddress(uint16_t port=0,bool loopbackOnly=false,bool ipv6=false); inetaddress(string ip,uint16_t port,bool ipv6=false); //建構函式,IPV4地址 explicit inetaddress(const struct sockaddr_in& addr) :m_addr(addr) {} //建構函式,IPV6地址 explicit inetaddress(const struct sockaddr_in6& addr) :m_addr6(addr) {} //返回地址族,IP,IP:port,port,sockaddr*資訊 sa_family_t family() const {return m_addr.sin_family;} string toIp() const; string toIpPort() const; uint16_t toPort() const; const struct sockaddr* getSockAddr() const { return sockets::sockaddr_cast(&m_addr6); } //設定IPV6 m_addr void setSockAddrInet6(const struct sockaddr_in6& addr6) { m_addr6=addr6; } //獲取m_addr.sin_addr.s_addr,即IP地址網路位元組序 uint32_t ipNetEndian() const; //獲取埠號的網路位元組序 uint16_t portEntEndian() const{return m_addr.sin_port;} //執行緒安全,完成主機名到IP地址的轉換,不改變埠號和地址族 //內部使用gethostbyname_r()實現 static bool resolve(string hostname,inetaddress* result); //設定 IPV6 ScopeId void setScopeId(uint32_t scope_id); private: union { //size分別是多少,待會測一下 //sockaddr:16,sockaddr_in:16,sockaddr_in6:28 struct sockaddr_in m_addr; struct sockaddr_in6 m_addr6; }; }; }//namespace net }//namespace mymuduo #endif // INETADDRESS_H
inet_address.cpp:
#include "inetaddress.h" #include"base/logging.h" #include"net/socketsops.h" #include"net/endian.h" #include<netdb.h> //變數(程式碼)級:指定某個變數警告 // INADDR_ANY use (type)value casting. #pragma GCC diagnostic ignored "-Wold-style-cast" static const in_addr_t kInaddrAny = INADDR_ANY; static const in_addr_t kInaddrLoopback = INADDR_LOOPBACK; #pragma GCC diagnostic error "-Wold-style-cast" // sockaddr_in,in_addr_t,sockaddr_in6結構 // /* Structure describing an Internet socket address. */ // struct sockaddr_in { // sa_family_t sin_family; /* address family: AF_INET */ // uint16_t sin_port; /* port in network byte order */ // struct in_addr sin_addr; /* internet address */ // }; // /* Internet address. */ // typedef uint32_t in_addr_t; // struct in_addr { // in_addr_t s_addr; /* address in network byte order */ // }; // struct sockaddr_in6 { // sa_family_t sin6_family; /* address family: AF_INET6 */ // uint16_t sin6_port; /* port in network byte order */ // uint32_t sin6_flowinfo; /* IPv6 flow information */ // struct in6_addr sin6_addr; /* IPv6 address */ // uint32_t sin6_scope_id; /* IPv6 scope-id */ // }; namespace mymuduo { namespace net{ //靜態編譯時斷言 static_assert(sizeof(inetaddress) == sizeof(struct sockaddr_in6), "InetAddress is same size as sockaddr_in6"); static_assert(offsetof(sockaddr_in, sin_family) == 0, "sin_family offset 0"); static_assert(offsetof(sockaddr_in6, sin6_family) == 0, "sin6_family offset 0"); static_assert(offsetof(sockaddr_in, sin_port) == 2, "sin_port offset 2"); static_assert(offsetof(sockaddr_in6, sin6_port) == 2, "sin6_port offset 2"); //explicit禁止隱式型別轉換 //建構函式,利用預設本地IP地址初始化m_addr6/m_addr inetaddress::inetaddress(uint16_t port,bool loopbackOnly,bool ipv6) { static_assert (offsetof(inetaddress,m_addr6)==0,"m_addr6 offset 0"); static_assert(offsetof(inetaddress,m_addr)==0,"m_addr offset 0"); //判斷是否是IPV6 if(ipv6) { memZero(&m_addr6,sizeof(m_addr6)); m_addr6.sin6_family=AF_INET6; m_addr6.sin6_port=sockets::hostToNetwork16(port); //是否是本地ip繫結,127.0.0.1 struct in6_addr ip=loopbackOnly?in6addr_loopback:in6addr_any; m_addr6.sin6_addr=ip; }else { memZero(&m_addr,sizeof(m_addr)); m_addr.sin_family=AF_INET; m_addr.sin_port=sockets::hostToNetwork16(port); //是否繫結本地 in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny; m_addr.sin_addr.s_addr=sockets::hostToNetwork32(ip); } } //建構函式,利用給定IP地址初始化m_addr6/m_addr inetaddress::inetaddress(string ip,uint16_t port,bool ipv6) { if(ipv6) { memZero(&m_addr6,sizeof(m_addr6)); sockets::fromIpPort(ip.data(),port,&m_addr6); }else { memZero(&m_addr,sizeof(m_addr)); sockets::fromIpPort(ip.data(),port,&m_addr); } } //返回IP地址字串 string inetaddress::toIp() const { char buf[64]={0}; sockets::toIp(buf,sizeof(buf),getSockAddr()); return buf; } //返回IP:port字串 string inetaddress::toIpPort() const { char buf[64]={0}; sockets::toIpPort(buf,sizeof(buf),getSockAddr()); return buf; } uint16_t inetaddress::toPort() const { return sockets::networkToHost16(portEntEndian()); } static __thread char t_resolveBuffer[64*1024]; //返回sockaddr的網路位元組序 uint32_t inetaddress::ipNetEndian() const { assert(family()==AF_INET); return m_addr.sin_addr.s_addr; } //執行緒安全,完成主機名到IP地址的轉換,不改變埠號和地址族 bool inetaddress::resolve(string hostname,inetaddress* out) { assert(out != NULL); struct hostent hent; struct hostent* he = NULL; int herrno = 0; memZero(&hent, sizeof(hent)); int ret = gethostbyname_r(hostname.c_str(), &hent, t_resolveBuffer, sizeof t_resolveBuffer, &he, &herrno); if (ret == 0 && he != NULL) { assert(he->h_addrtype == AF_INET && he->h_length == sizeof(uint32_t)); out->m_addr.sin_addr = *reinterpret_cast<struct in_addr*>(he->h_addr); return true; } else { if (ret) { LOG_SYSERR << "InetAddress::resolve"; } return false; } } //設定 IPV6 ScopeId void inetaddress::setScopeId(uint32_t scope_id) { if(family()==AF_INET6) m_addr6.sin6_scope_id=scope_id; } }//namespace net }//namespace mymuduo
測試:
#include"base/thread.h" #include"net/inetaddress.h" #include<iostream> using namespace mymuduo::net; int main() { inetaddress addr4_1(12306,true); std::cout<<addr4_1.toIpPort()<<std::endl; //用addr4_1的m_addr去構造addr4_2 inetaddress addr4_2(*(reinterpret_cast<const sockaddr_in*>(addr4_1.getSockAddr()))); std::cout<<addr4_2.toIpPort()<<std::endl; inetaddress addr4_3("192.168.1.103",12345); std::cout<<addr4_3.toIpPort()<<std::endl; }
列印結果:
127.0.0.1:12306
127.0.0.1:12306
192.168.1.103:12345