[sylar]C++高性能服务器框架——Address模块

748 阅读9分钟

Address模块概述

socket的通信都需要与地址打交道,所以封装了Address模块,不用进行繁琐的一系列操作。

Address模块有主要一下几类:

  • class Address:基类,抽象类,对应sockaddr类型。提供获取地址的方法,以及一些基础操作的纯虚函数。
  • class IPAddress:继承Address,抽象类。提供关于IP操作的纯虚函数。
  • class IPv4Address:继承IPAddress,对应sockaddr_in类型。一个IPv4地址。
  • class IPv6Address:继承IPAddress,对应sockaddr_in6类型。一个IPv6地址。
  • class UinxAddress:继承AddressUnix域套接字类,对应sockaddr_un类型。一个Unix地址。
  • class UnknowAddress:继承Address,对应sockaddr类型。未知地址。

socket地址结构体

sockaddrsockaddr_in都为16字节,sockaddr_in6为28字节。

如果要问为什么字节数不同还能相互转化,那是因为在进行类型转换时,只需要将指针类型进行转换即可,不需要改变结构体的大小。

/* Structure describing a generic socket address.  */
struct sockaddr
{
 uint16 sa_family;           /* Common data: address family and length.  */
 char sa_data[14];           /* Address data.  */
};
​
/* Structure describing an Internet socket address.  */
struct sockaddr_in
{
 uint16 sin_family;          /* Address family AF_INET */ 
 uint16 sin_port;            /* Port number.  */
 uint32 sin_addr.s_addr;     /* Internet address.  */
 unsigned char sin_zero[8];  /* Pad to size of `struct sockaddr'.  */
};
​
/* Ditto, for IPv6.  */
struct sockaddr_in6
{
 uint16 sin6_family;         /* Address family AF_INET6 */
 uint16 sin6_port;           /* Transport layer port # */
 uint32 sin6_flowinfo;       /* IPv6 flow information */
 uint8  sin6_addr[16];       /* IPv6 address */
 uint32 sin6_scope_id;       /* IPv6 scope-id */
};
​
struct in6_addr
  {
    union
      {
    uint8_t __u6_addr8[16];
    uint16_t __u6_addr16[8];
    uint32_t __u6_addr32[4];
      } __in6_u;
#define s6_addr         __in6_u.__u6_addr8
#ifdef __USE_MISC
# define s6_addr16      __in6_u.__u6_addr16
# define s6_addr32      __in6_u.__u6_addr32
#endif
  };
#endif /*

getaddrinfo

函数将主机名、主机地址、服务名和端口的字符串表示转换成套接字地址结构体,应用程序只要处理由getaddrinfo函数填写的套接口地址结构。

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>int getaddrinfo( const char *node, 
                 const char *service,
                 const struct addrinfo *hints,
                 struct addrinfo **res);
1)nodename:节点名可以是主机名,也可以是数字地址。(IPV4的10进点分,或是IPV6的16进制);
2)servname:包含十进制数的端口号或服务名如(ftp,http);
3)hints:是一个空指针或指向一个addrinfo结构的指针,由调用者填写关于它所想返回的信息类型的线索;
4)res:存放返回addrinfo结构链表的指针;
​
/*  释放addrinfo指针    */
void freeaddrinfo(struct addrinfo *res);
/*  getaddrinfo函数返回的错误码转换为对应的错误信息字符串    */
const char *gai_strerror(int errcode);
 
struct addrinfo {
      int              ai_flags;        // 位掩码,修改默认行为
      int              ai_family;       // socket()的第一个参数
      int              ai_socktype;     // socket()的第二个参数
      int              ai_protocol;     // socket()的第三个参数
      socklen_t        ai_addrlen;      // sizeof(ai_addr)
      struct sockaddr  *ai_addr;        // sockaddr指针
      char            *ai_canonname;    // 主机的规范名字
      struct addrinfo   *ai_next;       // 链表的下一个结点
}
​
参数说明:
ai_flags:
1)AI_ADDRCONFIG: 只有当本地主机被配置为IPv4时,getaddrinfo返回IPv4地址,IPv6同理。
2)AI_CANONNAME: ai_canonname默认为NULL,设置此标志位,告诉getaddrinfo将列表中第一个addrinfo结构体的ai_cannoname字段指向host的权威(官方)名字。
3)AI_NUMERICSERV: service默认为服务名或端口号。这个标志强制参数service为端口号。
4)AI_PASSIVE: getaddrinfo默认返回套接字地址,客户端可以在调用connect时用作主动套接字。此标志位告诉该函数,返回的套接字地址可能被服务器用作监听套接字。此时,host应该为NULL5)AI_NUMERICHOST:用于指示getaddrinfo函数在解析主机名时是否进行名称解析。当我们需要使用IP地址而不是主机名来创建套接字时,可以将AI_NUMERICHOST常量作为getaddrinfo函数的hints参数中的ai_flags成员的值,以指示getaddrinfo函数不进行主机名解析,而直接使用传入的IP地址。这样可以避免主机名解析带来的延迟和不确定性,提高套接字的创建效率和可靠性。

getifaddrs

函数用于获取系统中所有网络接口的信息。

#include <sys/types.h>
#include <ifaddrs.h>/*  getifaddrs创建一个链表,链表上的每个节点都是一个struct ifaddrs结构,getifaddrs()返回链表第一个元素的指针。
 *  成功返回0, 失败返回-1,同时errno会被赋允相应错误码。 */
int getifaddrs(struct ifaddrs **ifap);
​
/*  释放ifaddrs */
void freeifaddrs(struct ifaddrs *ifa);
​
struct ifaddrs {
   struct ifaddrs  *ifa_next;    /* 指向链表中下一个struct ifaddr结构 */
   char            *ifa_name;    /* 网络接口名 */
   unsigned int     ifa_flags;   /* 网络接口标志 */
   struct sockaddr *ifa_addr;    /* 指向一个包含网络地址的sockaddr结构 */
   struct sockaddr *ifa_netmask; /* 指向一个包含网络掩码的结构 */
   union {
       struct sockaddr *ifu_broadaddr;
                        /* 如果(ifa_flags&IFF_BROADCAST)有效,ifu_broadaddr指向一个包含广播地址的结构 */
       struct sockaddr *ifu_dstaddr;
                        /* 如果(ifa_flags&IFF_POINTOPOINT)有效,ifu_dstaddr指向一个包含p2p目的地址的结构 */
   } ifa_ifu;
#define              ifa_broadaddr ifa_ifu.ifu_broadaddr
#define              ifa_dstaddr   ifa_ifu.ifu_dstaddr
   void            *ifa_data;    /* 指向一个缓冲区,其中包含地址族私有数据。没有私有数据则为NULL */
};

详解

根据前缀长度创建掩码

/*
 *  sizeof(T) * 8: 算出有多少位
 *  sizeof(T) * 8 - bits: 算出掩码0的个数
 *  1 <<:1 左移0的个数位
 *  -1: 前bits位数置为0,后面的 sizeof(T) * 8 - bits 位都为1
 *  ~: 将前bits位置为1,后面全部置为0
 */
​
template<class T>
static T CreateMask(uint32_t bits) {
    return ~((1 << (sizeof(T) * 8 - bits)) - 1);
}

根据掩码计算前缀长度

template<class T>
static uint32_t CountBytes(T value) {
    uint32_t result = 0;
    for (; value; ++result) {
        // 将最右边的1置为0
        value &= value - 1;
    }
    return result;
}

class Address

提供三个纯虚函数

// 获得sockaddr指针
virtual const sockaddr* getAddr() const = 0;
// 获得sockaddr长度
virtual socklen_t getAddrLen() const = 0;
// 可读性输出地址
virtual std::ostream& insert(std::ostream& os) const = 0;

Create(通过sockaddr创建地址)

静态方法

Address::ptr Address::Create(const sockaddr* sockaddr, socklen_t addrlen) {
    if (sockaddr == nullptr) {
        return nullptr;
    }
​
    Address::ptr result;
    switch (sockaddr->sa_family) {
    case AF_INET:
        result.reset(new IPv4Address(*(const sockaddr_in*)sockaddr));
        break;
    case AF_INET6:
        result.reset(new IPv6Address(*(const sockaddr_in6*)sockaddr));
        break;
    default:
        result.reset(new UnknowAddress(*sockaddr));
        break;
    }
    return result;
}

Lookup(通过host地址返回所有Address)

静态方法

bool Address::Lookup(std::vector<Address::ptr>& result, const std::string& host,
                int family, int type, int protocol) {
    addrinfo hints, * results, * next;
    hints.ai_addr = NULL;
    hints.ai_addrlen = 0;
    hints.ai_canonname = NULL;
    hints.ai_family = family;
    hints.ai_flags = 0;
    hints.ai_next = NULL;
    hints.ai_protocol = protocol;
    hints.ai_socktype = type;
​
    std::string node;
    const char* service = nullptr;
​
    //  host = www.baidu.com:http
    //  检查 ipv6address service  [address]:
    if (!host.empty() && host[0] == '[') {
        // 查找第一个 ] 的位置,返回该指针
        const char* endipv6 = (const char*)memchr(host.c_str() + 1, ']', host.size() - 1);
        // 找到了 ]
        if (endipv6) {
            //  是否为 :
            if (*(endipv6 + 1) == ':') {
                //  endipv6后两个字节为端口号
                service = endipv6 + 2;
            }
            //  地址为[]里的内容
            node = host.substr(1, endipv6 - host.c_str() - 1);
        }
    }
​
    //  ipv4    ip:port
    if (node.empty()) {
        // 找到第一个:
        service = (const char*)memchr(host.c_str(), ':', host.size());
        // 找到了
        if (service) {
            // 后面没有 : 了
            if (!memchr(service + 1, ':', host.c_str() + host.size() - service - 1)) {
                // 拿到地址
                node = host.substr(0, service - host.c_str());
                // :后面就是端口号
                ++service;
            }
        }
    }
    // 如果没设置端口号,就将host赋给他
    if (node.empty()) {
        node = host;
    }
    // 获得地址链表
    int error = getaddrinfo(node.c_str(), service, &hints, &results);
    if (error) {
        SYLAR_LOG_ERROR(g_logger) << "Address::Lookup getaddress(" << host
            << ", " << family << ", " << type << ") error = " << error
            << ", gai_strerror = " << gai_strerror(error);
        return false;
    }
    
    // results指向头节点,用next遍历
    next = results;
    while (next) {
        // 将得到的地址创建出来放到result容器中
        result.push_back(Create(next->ai_addr, next->ai_addrlen));
        next = next->ai_next;
    }
    
    // 释放addrinfo指针
    freeaddrinfo(results);
    return true;
}

LookupAny(通过host返回任意Address)

静态方法

Address::ptr Address::LookupAny(const std::string& host, int family,
                            int type, int protocol) {
    std::vector<Address::ptr> result;
    if (Lookup(result, host, family, type, protocol)) {
        return result[0];
    }
    return nullptr;

}

LookupAnyIPAddress(通过host返回任意IPAddress)

静态方法

std::shared_ptr<IPAddress> Address::LookupAnyIPAddress(const std::string& host, int family,
                            int type, int protocol) {
    std::vector<Address::ptr> result;
    if (Lookup(result, host, family, type, protocol)) {
        for (auto& i : result) {
            IPAddress::ptr v = std::dynamic_pointer_cast<IPAddress>(i);
            if (v) {
                return v;
            }
        }
    }
    return nullptr;
}

GetInterfaceAddresses(返回本机所有网卡的<网卡名, 地址, 子网掩码位数>)

静态方法

bool Address::GetInterfaceAddresses(std::multimap<std::string,
                std::pair<Address::ptr, uint32_t> >& result, int family) {
    struct ifaddrs* next, * results;
    if (getifaddrs(&results) != 0) {
        SYLAR_LOG_ERROR(g_logger) << "Address::GetInterfaceAddress getifaddrs "
            << "errno = " << errno << ", strerrno = " << strerror(errno);

        return false;
    }
	
    try {
        // results指向头节点,用next遍历
        for (next = results; next; next = next->ifa_next) {
            Address::ptr addr;
            uint32_t prefix_length = ~0u;
            // 地址族确定 并且 该地址族与解析出来的不同
            if (family != AF_UNSPEC && family != next->ifa_addr->sa_family) {
                continue;
            }
            switch (next->ifa_addr->sa_family) {
                 	// IPv4
                case AF_INET:
                    {	
                        // 创建ipv4地址
                        addr = Create(next->ifa_addr, sizeof(sockaddr_in));
                        // 掩码地址
                        uint32_t netmask = ((sockaddr_in*)next->ifa_netmask)->sin_addr.s_addr;
                        // 前缀长度,网络地址的长度
                        prefix_length = CountBytes(netmask);
                    }
                    break;
                    // IPv6
                case AF_INET6:
                    {	
                        // 创建ipv6地址
                        addr = Create(next->ifa_addr, sizeof(sockaddr_in6));
                        // 掩码地址
                        in6_addr& netmask = ((sockaddr_in6*)next->ifa_netmask)->sin6_addr;
                        prefix_length = 0;
                        // 前缀长度,16字节挨个算
                        for (int i = 0; i < 16; ++i) {
                            prefix_length += CountBytes(netmask.__in6_u.__u6_addr8[i]);
                        }
                    }
                    break;
                default:
                    break;
            }
            //	插入到容器中,保存了网卡名,地址和前缀长度
            if (addr) {
                result.insert(std::make_pair(next->ifa_name, std::make_pair(addr, prefix_length)));
            }
        }
    }
    catch (...) {
        SYLAR_LOG_ERROR(g_logger) << "Address::GetInterfaceAddresses exception";
        freeifaddrs(results);
        return false;
    }
	
    // 释放results
    freeifaddrs(results);
    return true;
}

GetInterfaceAddresses(获取指定网卡的地址和子网掩码位数)

bool Address::GetInterfaceAddresses(std::vector<std::pair<Address::ptr, uint32_t> >& result,
    const std::string& iface, int family) {
    if (iface.empty() || iface == "*") {
        //	创建监听任意IP地址的连接请求的ipv4
        if (family == AF_INET || family == AF_UNSPEC) {
            result.push_back(std::make_pair(Address::ptr(new IPv4Address()), 0u));
        }
        //	创建监听任意IP地址的连接请求的ipv6
        if (family == AF_INET6 || family == AF_UNSPEC) {
            result.push_back(std::make_pair(Address::ptr(new IPv6Address()), 0u));
        }
        return true;
    }
	
    std::multimap<std::string, std::pair<Address::ptr, uint32_t> >results;
    // 获取失败
    if (!GetInterfaceAddresses(results, family)) {
        return false;
    }
	
    // 返回pair,first为第一个等于的迭代器,second为第一个大于的迭代器
    auto its = results.equal_range(iface);
    // 将first与second之间的全部拿出来
    for (; its.first != its.second; ++its.first) {
        result.push_back(its.first->second);
    }
    return true;
}

getFamily(返回协议簇)

int Address::getFamily() const {
    return getAddr()->sa_family;
}

toString(返回可读性字符串)

std::string Address::toString() const {
    std::stringstream ss;
    insert(ss);
    return ss.str();
}

class IPAddress

提供5个纯虚函数

// 获得广播地址
virtual IPAddress::ptr broadcastAddress(uint32_t prefix_len) = 0;
// 获得网络地址
virtual IPAddress::ptr networkAddress(uint32_t prefix_len) = 0;
// 获得子网掩码地址
virtual IPAddress::ptr subnetMask(uint32_t prefix_len) = 0;
// 获得端口号
virtual uint16_t getPort() const = 0;
// 设置端口号
virtual void setPort(uint16_t v) = 0;

Create(通过IP、域名、服务器名,端口号创建IPAddress)

静态方法

IPAddress::ptr IPAddress::Create(const char* address, uint16_t port) {
    addrinfo hints;
    addrinfo* results;
    memset(&hints, 0, sizeof(hints));

    // 协议无关
    hints.ai_family = AF_UNSPEC;

    int error = getaddrinfo(address, "http", &hints, &results);
    if (error) {
        SYLAR_LOG_ERROR(g_logger) << "IPAddress::Create(" << address
            << ", " << port << ") error = " << error
            << ", gai_strerror = " << gai_strerror(error);
        return nullptr;
    }

    try {
        IPAddress::ptr result = std::dynamic_pointer_cast<IPAddress>(
            Address::Create(results->ai_addr, (socklen_t)results->ai_addrlen)
        );

        if (result) {
            result->setPort(port);
        }
        freeaddrinfo(results);
        return result;
    } catch (...) {
        freeaddrinfo(results);
        return nullptr;
    }
}

class IPv4Address

mumber(成员变量)

// sockaddr_in 结构体
sockaddr_in m_addr;

Create(通过IP,端口号创建IPv4Address)

静态方法

IPv4Address::ptr IPv4Address::Create(const char* address, uint16_t port) {
    IPv4Address::ptr rt(new IPv4Address);
    rt->m_addr.sin_port = byteswapOnLittleEndian(port);
    // 将一个IP地址的字符串表示转换为网络字节序的二进制形式
    int result = inet_pton(AF_INET, address, &rt->m_addr.sin_addr.s_addr);
    if (result <= 0) {
        SYLAR_LOG_ERROR(g_logger) << "IPv4Address::Create(" << address << ", "
            << port << ") rt = " << result << " errno = " << errno
            << " strerror = " << strerror(errno);
        return nullptr;
    }
    return rt;
}

IPv4Address(构造函数)

// 通过sockaddr_in
IPv4Address::IPv4Address(const sockaddr_in& sockaddr) {
    m_addr = sockaddr;
}

// 通过ip地址和端口号
IPv4Address::IPv4Address(uint32_t address, uint16_t port) {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sin_family = AF_INET;
    m_addr.sin_port = byteswapOnLittleEndian(port);
    m_addr.sin_addr.s_addr = byteswapOnLittleEndian(address);
}

getAddr(返回sockaddr指针)

const sockaddr* IPv4Address::getAddr() const {
    return (sockaddr*)&m_addr;
}

getAddrLen(返回sockaddr的长度)

socklen_t IPv4Address::getAddrLen() const  {
    return sizeof(m_addr);
}

insert(可读性输出地址)

std::ostream& IPv4Address::insert(std::ostream& os) const {
    uint32_t addr = byteswapOnLittleEndian(m_addr.sin_addr.s_addr);
    os << ((addr >> 24) & 0xff) << "."
        << ((addr >> 16) & 0xff) << "."
        << ((addr >> 8) & 0xff) << "."
        << (addr & 0xff);
    os << ": " << byteswapOnLittleEndian(m_addr.sin_port);
    return os;
}

broadcastAddress(返回广播地址)

IPAddress::ptr IPv4Address::broadcastAddress(uint32_t prefix_len) {
    if (prefix_len > 32) {
        return nullptr;
    }
    
    sockaddr_in baddr(m_addr);
    // 主机号全为1
    baddr.sin_addr.s_addr |= ~byteswapOnLittleEndian(
        CreateMask<uint32_t>(prefix_len));

    return IPv4Address::ptr(new IPv4Address(baddr));
}

networkAddress(返回网络地址)

IPAddress::ptr IPv4Address::networkAddress(uint32_t prefix_len) {
    if (prefix_len > 32) {
        return nullptr;
    }
    
    sockaddr_in naddr(m_addr);
    // 主机号全为0
    naddr.sin_addr.s_addr &= byteswapOnLittleEndian(
        CreateMask<uint32_t>(prefix_len));

    return IPv4Address::ptr(new IPv4Address(naddr));
}

subnetMask(返回子网掩码地址)

IPAddress::ptr IPv4Address::subnetMask(uint32_t prefix_len) {
    sockaddr_in subnet;
    memset(&subnet, 0, sizeof(subnet));
    subnet.sin_family = AF_INET;
    // 根据前缀长度获得子网掩码
    subnet.sin_addr.s_addr = byteswapOnLittleEndian(CreateMask<uint32_t>(prefix_len));
    return IPv4Address::ptr(new IPv4Address(subnet));
}

getPort(返回端口号)

uint16_t IPv4Address::getPort() const {
    return byteswapOnLittleEndian(m_addr.sin_port);
}

setPort(设置端口号)

void IPv4Address::setPort(uint16_t v) {
    m_addr.sin_port = byteswapOnLittleEndian(v);
}

class IPv6Address

mumber(成员变量)

// sockaddr_in6 结构体
sockaddr_in6 m_addr;

Create(通过IPv6地址字符串构造IPv6Address)

静态方法

IPv6Address::ptr IPv6Address::Create(const char* address, uint16_t port) {
    IPv6Address::ptr rt(new IPv6Address);
    rt->m_addr.sin6_port = byteswapOnLittleEndian(port);
    int result = inet_pton(AF_INET6, address, &rt->m_addr.sin6_addr.__in6_u.__u6_addr8);
    if (result <= 0) {
        SYLAR_LOG_ERROR(g_logger) << "IPv4Address::Create(" << address << ", "
            << port << ") rt = " << result << " errno = " << errno
            << " strerror = " << strerror(errno);
        return nullptr;
    }
    return rt;
}

IPv6Address(构造函数)

// 默认构造函数
IPv6Address::IPv6Address() {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sin6_family = AF_INET6;
}

// 通过sockaddr_in6
IPv6Address::IPv6Address(const sockaddr_in6& sockaddr) {
    m_addr = sockaddr;
}

// 通过address和port
IPv6Address::IPv6Address(const uint8_t address[16], uint16_t port) {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sin6_family = AF_INET6;
    m_addr.sin6_port = byteswapOnLittleEndian(port);
    memcpy(&m_addr.sin6_addr.__in6_u.__u6_addr8, address, 16);
}

getAddr(返回sockaddr指针)

const sockaddr* IPv6Address::getAddr() const {
    return (sockaddr*)&m_addr;
}

getAddrLen(返回sockaddr的长度)

socklen_t IPv6Address::getAddrLen() const  {
    return sizeof(m_addr);
}

insert(可读性输出地址)

std::ostream& IPv6Address::insert(std::ostream& os) const {
    os << "[";
    // 两个字节为一块
    uint16_t* addr = (uint16_t*)m_addr.sin6_addr.__in6_u.__u6_addr8;
    bool used_zeros = false;
    for (int i = 0; i < 8; ++i) {
        // 将连续0块省略
        if (addr[i] == 0 && !used_zeros) {
            continue;
        }
        // 上一块为0,多输出个:
        if (i && addr[i - 1] == 0 && !used_zeros) {
            os << ":";
            // 省略过了,后面不能再省略连续0块了
            used_zeros = true;
        }
        // 每个块后都要输出:
        if (i) {
            os << ":";
        }
        // 按十六进制输出
        os << std::hex << (int)byteswapOnLittleEndian(addr[i]) << std::dec;
    }
	
    // 若最后一块为0省略
    if (!used_zeros && addr[7] == 0) {
        os << "::";
    }

    os << "]: " << byteswapOnLittleEndian(m_addr.sin6_port);
    return os;
}

broadcastAddress(返回广播地址)

IPAddress::ptr IPv6Address::broadcastAddress(uint32_t prefix_len) {
    sockaddr_in6 baddr(m_addr);
    /*	找到前缀长度结尾在第几个字节,在该字节在哪个位置。
     *	将该字节前剩余位置全部置为1	*/
    baddr.sin6_addr.__in6_u.__u6_addr8[prefix_len / 8] |=
        ~CreateMask<uint8_t>(prefix_len % 8);
	
    // 将后面其余字节置为1
    for (int i = prefix_len / 8 + 1; i < 16; ++i) {
        baddr.sin6_addr.__in6_u.__u6_addr8[i] = 0xff;
    }

    return IPv6Address::ptr(new IPv6Address(baddr));
}

networkAddress(返回网络地址)

IPAddress::ptr IPv6Address::networkAddress(uint32_t prefix_len) {
    sockaddr_in6 naddr(m_addr);
    /*	找到前缀长度结尾在第几个字节,在该字节在哪个位置。
     *	将该字节前剩余位置全部置为0	*/
    naddr.sin6_addr.__in6_u.__u6_addr8[prefix_len / 8] &=
        CreateMask<uint8_t>(prefix_len % 8);
	
    // 将后面其余字节置为0
    for (int i = prefix_len / 8 + 1; i < 16; ++i) {
        naddr.sin6_addr.__in6_u.__u6_addr8[i] = 0x00;
    }

    return IPv6Address::ptr(new IPv6Address(naddr));
}

subnetMask(返回子网掩码地址)

IPAddress::ptr IPv6Address::subnetMask(uint32_t prefix_len) {
    sockaddr_in6 subnet;
    memset(&subnet, 0, sizeof(subnet));
    subnet.sin6_family = AF_INET6;
    /*	找到前缀长度结尾在第几个字节,在该字节在哪个位置  */
    subnet.sin6_addr.__in6_u.__u6_addr8[prefix_len / 8] =
        CreateMask<uint8_t>(prefix_len % 8);
	
    // 将前面的字节全部置为1
    for (int i = 0; i < (int32_t)prefix_len / 8; ++i) {
        subnet.sin6_addr.__in6_u.__u6_addr8[i] = 0xff;
    }
    return IPv6Address::ptr(new IPv6Address(subnet));
}

getPort(返回端口号)

uint16_t IPv6Address::getPort() const {
    return byteswapOnLittleEndian(m_addr.sin6_port);
}

setPort(设置端口号)

void IPv6Address::setPort(uint16_t v) {
    m_addr.sin6_port = byteswapOnLittleEndian(v);
}

class UinxAddress

mumber(成员变量)

// sockaddr_un 结构体
struct sockaddr_un m_addr;
// 长度
socklen_t m_length;

UinxAddress(构造函数)

// Unix域套接字路径名的最大长度。-1是减去'\0'
static const size_t MAX_PATH_LEN = sizeof(((sockaddr_un*)0)->sun_path) - 1;

// 默认构造
UinxAddress::UinxAddress() {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sun_family = AF_UNIX;
    // sun_path的偏移量+最大路径
    m_length = offsetof(sockaddr_un, sun_path) + MAX_PATH_LEN;
}

// 通过路径
UinxAddress::UinxAddress(const std::string& path) {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sun_family = AF_UNIX;
    // 加上'\0'的长度
    m_length = path.size() + 1;

    if (!path.empty() && path[0] == '\0') {
        --m_length;
    }

    if (m_length > sizeof(m_addr.sun_path)) {
        throw std::logic_error("path too long");
    }
    // 将path放入结构体
    memcpy(m_addr.sun_path, path.c_str(), m_length);
    // 偏移量+路径长度
    m_length += offsetof(sockaddr_un, sun_path);
}

getAddrLen(设置sockaddr的长度)

void UinxAddress::setAddrlen(uint32_t v) {
    m_length = v;
}

getAddr(返回sockaddr指针)

const sockaddr* UinxAddress::getAddr() const {
    return (sockaddr*)&m_addr;
}

getAddrLen(返回sockaddr的长度)

socklen_t UinxAddress::getAddrLen() const {
    return m_length;
}

insert(可读性输出地址)

std::ostream& UinxAddress::insert(std::ostream& os) const {
    if (m_length > offsetof(sockaddr_un, sun_path)
        && m_addr.sun_path[0] == '\0') {
        return os << "\0" << std::string(m_addr.sun_path + 1,
            m_length - offsetof(sockaddr_un, sun_path) - 1);
    }
    return os << m_addr.sun_path;
}

总结

通过静态方法能够通过域名、IP、主机名获得对应Address

void test() {
    SYLAR_LOG_INFO(g_logger) << "begin";

    std::vector<sylar::Address::ptr> addrs;
    bool v = sylar::Address::Lookup(addrs, "www.baidu.com", AF_INET, SOCK_STREAM);
    if (!v) {
        SYLAR_LOG_ERROR(g_logger) << "lookup fail";
    }

    for (size_t i = 0; i < addrs.size(); ++i) {
        SYLAR_LOG_INFO(g_logger) << i << " - " << addrs[i]->toString();
    }
}

通过静态方法获得本机的Address

void test_iface() {
    std::multimap<std::string, std::pair<sylar::Address::ptr, uint32_t> >results;

    bool v = sylar::Address::GetInterfaceAddresses(results);
    if (!v) {
        SYLAR_LOG_ERROR(g_logger) << "GetInterfaceAddresses fail";
    }
    for (auto& i : results) {
        SYLAR_LOG_INFO(g_logger) << i.first << " - " << i.second.first->toString() << " - " << i.second.second;
    }
}

通过静态方法获取IPAddress

void test_ip() {
    auto addr = sylar::IPAddress::Create("www.baidu.com");
    if (addr) {
        SYLAR_LOG_INFO(g_logger) << addr->toString();
    }
}

创建IPv4地址

void test_ipv4() {
    auto addr = sylar::IPv4Address::Create("112.80.248.75", 80);
    auto saddr = addr->subnetMask(24);
    auto baddr = addr->broadcastAddress(24);
    auto naddr = addr->networkAddress(24);
    if (addr) {
        SYLAR_LOG_INFO(g_logger) << addr->toString();
    }
    if (saddr) {
        SYLAR_LOG_INFO(g_logger) << saddr->toString();
    }
    if (baddr) {
        SYLAR_LOG_INFO(g_logger) << baddr->toString();
    }
    if (naddr) {
        SYLAR_LOG_INFO(g_logger) << naddr->toString();
    }
}

创建IPv6地址

void test_ipv6() {
    auto addr = sylar::IPv6Address::Create("fe80::215:5dff:fe20:e26a", 8020);
    if (addr) {
        SYLAR_LOG_INFO(g_logger) << addr->toString();
    }
    auto saddr = addr->subnetMask(64);
    auto baddr = addr->broadcastAddress(64);
    auto naddr = addr->networkAddress(64);
    if (addr) {
        SYLAR_LOG_INFO(g_logger) << addr->toString();
    }
    if (saddr) {
        SYLAR_LOG_INFO(g_logger) << saddr->toString();
    }
    if (baddr) {
        SYLAR_LOG_INFO(g_logger) << baddr->toString();
    }
    if (naddr) {
        SYLAR_LOG_INFO(g_logger) << naddr->toString();
    }
}