muduo源码解析20-inetaddress类
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*等一些函数用于获取信息
内部实现基本用sockets命名空间中的一些封装来实现
成员变量:
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 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);
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

浙公网安备 33010602011771号