Sylar C++高性能服务器学习记录18 【Address模块-代码分析篇】

早在19年5月就在某站上看到sylar的视频了,一直认为这是一个非常不错的视频。
由于本人一直是自学编程,基础不扎实,也没有任何人的督促,没能坚持下去。
每每想起倍感惋惜,遂提笔再续前缘。

为了能更好的看懂sylar,本套笔记会分两步走,每个系统都会分为两篇博客。
分别是【知识储备篇】和【代码分析篇】
(ps:纯粹做笔记的形式给自己记录下,欢迎大家评论,不足之处请多多赐教)
QQ交流群:957100923


Address模块-代码分析篇

一、substr函数的补充说明

用于从字符串中提取子字符串。它的具体功能是返回一个新的字符串,该字符串包含原始字符串中从指定位置开始的指定长度的字符。

substr 函数有两种常用的用法:
1.substr(pos, len): 从指定位置pos开始,提取长度为len的子字符串。
2.substr(pos): 从指定位置pos开始,提取到原始字符串的末尾的子字符串。
以上是比较官方的解释

但在Sylar中我看到有这样一行,其中 endipv6 - host.c_str() - 1 是一个负数,让我很费解
由于自己基础知识不太扎实,所以做了个实验,来帮助我理解 substr 函数

node = host.substr(1, endipv6 - host.c_str() - 1);

其实就是 substr 的第二个参数如果是负数的情况,结果会是怎么样?

std::string str = "hello,world";
std::string sub = str.substr(6,-5);
std::cout << sub << std::endl;

输出:

world

可以看到,结果和 str.substr(6,5) 是一样的
所以我大胆的推测 第二个参数会取模操作


二、根据子网掩码的十进制数,取子网掩码的位数

这里我列出了所有的子网掩码
可以看出其规律是:连续的1和0构成,且高位是1低位是0

位数点分十进制二进制十进制
8位子网掩码255.0.0.011111111 00000000 00000000 000000004278190080
9位子网掩码255.128.0.011111111 10000000 00000000 000000004286578688
10位子网掩码255.192.0.011111111 11000000 00000000 000000004290772992
11位子网掩码255.224.0.011111111 11100000 00000000 000000004292870144
12位子网掩码255.240.0.011111111 11110000 00000000 000000004293918720
13位子网掩码255.248.0.011111111 11111000 00000000 000000004294443008
14位子网掩码255.252.0.011111111 11111100 00000000 000000004294705152
15位子网掩码255.254.0.011111111 11111110 00000000 000000004294836224
16位子网掩码255.255.0.011111111 11111111 00000000 000000004294901760
17位子网掩码255.255.128.011111111 11111111 10000000 000000004294934528
18位子网掩码255.255.192.011111111 11111111 11000000 000000004294950912
19位子网掩码255.255.224.011111111 11111111 11100000 000000004294959104
20位子网掩码255.255.240.011111111 11111111 11110000 000000004294963200
21位子网掩码255.255.248.011111111 11111111 11111000 000000004294965248
22位子网掩码255.255.252.011111111 11111111 11111100 000000004294966272
23位子网掩码255.255.254.011111111 11111111 11111110 000000004294966784
24位子网掩码255.255.255.011111111 11111111 11111111 000000004294967040
25位子网掩码255.255.255.12811111111 11111111 11111111 100000004294967168
26位子网掩码255.255.255.19211111111 11111111 11111111 110000004294967232
27位子网掩码255.255.255.22411111111 11111111 11111111 111000004294967264
28位子网掩码255.255.255.24011111111 11111111 11111111 111100004294967280
29位子网掩码255.255.255.24811111111 11111111 11111111 111110004294967288
30位子网掩码255.255.255.25211111111 11111111 11111111 111111004294967292
31位子网掩码255.255.255.25411111111 11111111 11111111 111111104294967294
32位子网掩码255.255.255.25511111111 11111111 11111111 111111114294967295

假如我们得到十进制数,需要算出其子网掩码的位数,该怎么办呢?
我们先做个实验:

1.有十进制数:3,他的二进制为 11 我们做如下操作:(可以看到我们做了2次 &= 操作 num 才为 0)

uint32_t num = 3;
num &= num-1;		//num = 2;
num &= num-1;		//num = 0;

2.有十进制数:7,他的二进制为 111 我们做如下操作:(可以看到我们做了3次 &= 操作 num 才为 0)

uint32_t num = 7;
num &= num-1;		//num = 6;
num &= num-1;		//num = 4;
num &= num-1;		//num = 0;

3.有十进制数:15,他的二进制为 1111 我们做如下操作:(可以看到我们做了4次 &= 操作 num 才为 0)

uint32_t num = 15;
num &= num-1;		//num = 14;
num &= num-1;		//num = 12;
num &= num-1;		//num = 8;
num &= num-1;		//num = 0;

结论:十进制数 num 通过 n次 num&= num-1 操作 将 num 变成 0,那么 n 就是其中该二进制数中1的出现次数!
通过该结论我们可以巧妙的将子网掩码的十进制数通过循环进行&=操作,统计等于0时的次数来算出子网掩码的位数

我们可以设计以下代码:

//子网掩码位数
uint32_t mask_byte_count = 0;
//子网掩码 255.255.255.0 也就是24位子网掩码
uint32_t mask_number = 4294967040;

for; mask_number; ++mask_byte_count){
	mask_number &= mask_number-1;
}

std::cout << mask_byte_count<< std::endl;

输出为:(对应上表,可以查询到 4294967040 对应的子网掩码位数就是 24)

24

所以说,Sylar的功力 可见一斑 短短的几行代码就让我啃了很久。
对于跟我一样基础知识不扎实的兄弟们我有句话想问:“这一拳,十年的功力,敢问阁下如何应对!”


三、根据子网掩码的位数,取子网掩码的十进制数

上述功能是根据十进制的子网掩码获取子网掩码的位数
那么我们也要有相应的根据子网掩码的位数获取子网掩码的十进制数

依旧做实验:

1.假设有个4位二进制数其中1的个数是1个,我们该如何反推出其十进制数呢?
这个口算一下:得出二进制是 1000 再口算得出十进制数 8

2.假设有个4位二进制数其中1的个数是2个,我们该如何反推出其十进制数呢?
这个口算一下:得出二进制是 1100 再口算得出十进制数 12

3.假设有个4位二进制数其中1的个数是3个,我们该如何反推出其十进制数呢?
这个口算一下:得出二进制是 1110 再口算得出十进制数 14

那么我们是否可以做一个公式呢?(公式的推导恕我没法想到,这里直接用sylar的源码了)

//根据高位1的个数推算出,对应低位全1,高位为0 的十进制数(用于后续取反)
uint32_t bits2decimal(uint32_t bits) {
    return (1 << (sizeof(uint32_t) * 8 - bits)) - 1;
}

//这里取反
uint32_t mask = ~bits2decimal(24);

std::cout << mask << std::endl;

结论:愈发觉得Sylar的基本功扎实,自愧不如,做不了先驱就要学会跟着先驱的脚步前行。


四、Address模块类的设计(以下内容来自一位 “先行者” 的博客 总结)

Address类

这个类是所有网络地址类的基类,并且是一个抽象类,对应的是sockaddr,表示通用网络地址。
对于一个通用的网络地址,需要关注它的地址类型,sockaddr指针,地址长度这几项内容。
除此外,Address类还提供了地址解析与本机网卡地址查询的功能,地址解析功能可以实现域名解析,
网卡地址查询可以获取本机指定网卡的IP地址。

IPAddress类

继承自Address类,表示一个IP地址,同样是一个抽象类,因为IP地址包含IPv4地址和IPv6地址。
IPAddress类提供了IP地址相关的端口和掩码、网段地址、网络地址操作,
无论是IPv4还是IPv6都支持这些操作,但这些方法都是抽象方法,需要由继承类来实现。

IPv4Address类

继承自IPAddress类,表示一个IPv4地址,到这一步,IPv4Address就是一个实体类了,
它包含一个sockaddr_in类型的成员,并且提供具体的端口设置/获取,掩码、网段、网络地址设置/获取操作。

IPv6Address类

继承自IPAddress类,表示一个IPv6地址,也是一个实体类,实现思路和IPv4Address一致。

UnixAddress类

继承自Address类,表示一个Unix域套接字地址,是一个实体类,可以用于实例化对象。
UnixAddress类包含一个sockaddr_un对象以及一个路径字符串长度。

UnknownAddress类

继承自Address类,包含一个sockaddr成员,表示未知的地址类型。


五、部分代码

endian.h (字节序操作函数(大端/小端))

#ifndef __SYLAR_ENDIAN_H__
#define __SYLAR_ENDIAN_H__

#define SYLAR_LITTLE_ENDIAN 1
#define SYLAR_BIG_ENDIAN 2

#include <byteswap.h>
#include <stdint.h>

namespace sylar {

/**
 * @brief 8字节类型的字节序转化
 */
template <class T>
typename std::enable_if<sizeof(T) == sizeof(uint64_t), T>::type
byteswap(T value) {
    return (T)bswap_64((uint64_t)value);
}

/**
 * @brief 4字节类型的字节序转化
 */
template <class T>
typename std::enable_if<sizeof(T) == sizeof(uint32_t), T>::type
byteswap(T value) {
    return (T)bswap_32((uint32_t)value);
}

/**
 * @brief 2字节类型的字节序转化
 */
template <class T>
typename std::enable_if<sizeof(T) == sizeof(uint16_t), T>::type
byteswap(T value) {
    return (T)bswap_16((uint16_t)value);
}

#if BYTE_ORDER == BIG_ENDIAN
#define SYLAR_BYTE_ORDER SYLAR_BIG_ENDIAN
#else
#define SYLAR_BYTE_ORDER SYLAR_LITTLE_ENDIAN
#endif

#if SYLAR_BYTE_ORDER == SYLAR_BIG_ENDIAN

/**
 * @brief 只在小端机器上执行byteswap, 在大端机器上什么都不做
 */
template <class T>
T byteswapOnLittleEndian(T t) {
    return t;
}

/**
 * @brief 只在大端机器上执行byteswap, 在小端机器上什么都不做
 */
template <class T>
T byteswapOnBigEndian(T t) {
    return byteswap(t);
}
#else

/**
 * @brief 只在小端机器上执行byteswap, 在大端机器上什么都不做
 */
template <class T>
T byteswapOnLittleEndian(T t) {
    return byteswap(t);
}

/**
 * @brief 只在大端机器上执行byteswap, 在小端机器上什么都不做
 */
template <class T>
T byteswapOnBigEndian(T t) {
    return t;
}
#endif

} 
#endif

address.h

#ifndef __SYLAR_ADDRESS_H__
#define __SYLAR_ADDRESS_H__

#include <memory>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <map>

namespace sylar {

class IPAddress;

/**
 * @brief 网络地址的基类,抽象类
 */
class Address {
public:
    typedef std::shared_ptr<Address> ptr;

    /**
     * @brief 通过sockaddr指针创建Address
     * @param[in] addr sockaddr指针
     * @param[in] addrlen sockaddr的长度
     * @return 返回和sockaddr相匹配的Address,失败返回nullptr
     */
    static Address::ptr Create(const sockaddr *addr, socklen_t addrlen);

    /**
     * @brief 通过host地址返回对应条件的所有Address
     * @param[out] result 保存满足条件的Address
     * @param[in] host 域名,服务器名等.举例: www.sylar.top[:80] (方括号为可选内容)
     * @param[in] family 协议族(AF_INT, AF_INT6, AF_UNIX)
     * @param[in] type socketl类型SOCK_STREAM、SOCK_DGRAM 等
     * @param[in] protocol 协议,IPPROTO_TCP、IPPROTO_UDP 等
     * @return 返回是否转换成功
     */
    static bool Lookup(std::vector<Address::ptr> &result, const std::string &host,
                       int family = AF_INET, int type = 0, int protocol = 0);
    /**
     * @brief 通过host地址返回对应条件的任意Address
     * @param[in] host 域名,服务器名等.举例: www.sylar.top[:80] (方括号为可选内容)
     * @param[in] family 协议族(AF_INT, AF_INT6, AF_UNIX)
     * @param[in] type socketl类型SOCK_STREAM、SOCK_DGRAM 等
     * @param[in] protocol 协议,IPPROTO_TCP、IPPROTO_UDP 等
     * @return 返回满足条件的任意Address,失败返回nullptr
     */
    static Address::ptr LookupAny(const std::string &host,
                                  int family = AF_INET, int type = 0, int protocol = 0);
    /**
     * @brief 通过host地址返回对应条件的任意IPAddress
     * @param[in] host 域名,服务器名等.举例: www.sylar.top[:80] (方括号为可选内容)
     * @param[in] family 协议族(AF_INT, AF_INT6, AF_UNIX)
     * @param[in] type socketl类型SOCK_STREAM、SOCK_DGRAM 等
     * @param[in] protocol 协议,IPPROTO_TCP、IPPROTO_UDP 等
     * @return 返回满足条件的任意IPAddress,失败返回nullptr
     */
    static std::shared_ptr<IPAddress> LookupAnyIPAddress(const std::string &host,
                                                         int family = AF_INET, int type = 0, int protocol = 0);

    /**
     * @brief 返回本机所有网卡的<网卡名, 地址, 子网掩码位数>
     * @param[out] result 保存本机所有地址
     * @param[in] family 协议族(AF_INT, AF_INT6, AF_UNIX)
     * @return 是否获取成功
     */
    static bool GetInterfaceAddresses(std::multimap<std::string, std::pair<Address::ptr, uint32_t>> &result,
                                      int family = AF_INET);
    /**
     * @brief 获取指定网卡的地址和子网掩码位数
     * @param[out] result 保存指定网卡所有地址
     * @param[in] iface 网卡名称
     * @param[in] family 协议族(AF_INT, AF_INT6, AF_UNIX)
     * @return 是否获取成功
     */
    static bool GetInterfaceAddresses(std::vector<std::pair<Address::ptr, uint32_t>> &result, const std::string &iface, int family = AF_INET);

    /**
     * @brief 虚析构函数
     */
    virtual ~Address() {}

    /**
     * @brief 返回协议簇
     */
    int getFamily() const;

    /**
     * @brief 返回sockaddr指针,只读
     */
    virtual const sockaddr *getAddr() const = 0;

    /**
     * @brief 返回sockaddr指针,读写
     */
    virtual sockaddr *getAddr() = 0;

    /**
     * @brief 返回sockaddr的长度
     */
    virtual socklen_t getAddrLen() const = 0;

    /**
     * @brief 可读性输出地址
     */
    virtual std::ostream &insert(std::ostream &os) const = 0;

    /**
     * @brief 返回可读性字符串
     */
    std::string toString() const;

    /**
     * @brief 小于号比较函数
     */
    bool operator<(const Address &rhs) const;

    /**
     * @brief 等于函数
     */
    bool operator==(const Address &rhs) const;

    /**
     * @brief 不等于函数
     */
    bool operator!=(const Address &rhs) const;
};

/**
 * @brief IP地址的基类
 */
class IPAddress : public Address {
public:
    typedef std::shared_ptr<IPAddress> ptr;

    /**
     * @brief 通过域名,IP,服务器名创建IPAddress
     * @param[in] address 域名,IP,服务器名等.举例: www.sylar.top
     * @param[in] port 端口号
     * @return 调用成功返回IPAddress,失败返回nullptr
     */
    static IPAddress::ptr Create(const char *address, uint16_t port = 0);

    /**
     * @brief 获取该地址的广播地址
     * @param[in] prefix_len 子网掩码位数
     * @return 调用成功返回IPAddress,失败返回nullptr
     */
    virtual IPAddress::ptr broadcastAddress(uint32_t prefix_len) = 0;

    /**
     * @brief 获取该地址的网段
     * @param[in] prefix_len 子网掩码位数
     * @return 调用成功返回IPAddress,失败返回nullptr
     */
    virtual IPAddress::ptr networkAddress(uint32_t prefix_len) = 0;

    /**
     * @brief 获取子网掩码地址
     * @param[in] prefix_len 子网掩码位数
     * @return 调用成功返回IPAddress,失败返回nullptr
     */
    virtual IPAddress::ptr subnetMask(uint32_t prefix_len) = 0;

    /**
     * @brief 返回端口号
     */
    virtual uint32_t getPort() const = 0;

    /**
     * @brief 设置端口号
     */
    virtual void setPort(uint16_t v) = 0;
};

/**
 * @brief IPv4地址
 */
class IPv4Address : public IPAddress {
public:
    typedef std::shared_ptr<IPv4Address> ptr;

    /**
     * @brief 使用点分十进制地址创建IPv4Address
     * @param[in] address 点分十进制地址,如:192.168.1.1
     * @param[in] port 端口号
     * @return 返回IPv4Address,失败返回nullptr
     */
    static IPv4Address::ptr Create(const char *address, uint16_t port = 0);

    /**
     * @brief 通过sockaddr_in构造IPv4Address
     * @param[in] address sockaddr_in结构体
     */
    IPv4Address(const sockaddr_in &address);

    /**
     * @brief 通过二进制地址构造IPv4Address
     * @param[in] address 二进制地址address
     * @param[in] port 端口号
     */
    IPv4Address(uint32_t address = INADDR_ANY, uint16_t port = 0);

    const sockaddr *getAddr() const override;
    sockaddr *getAddr() override;
    socklen_t getAddrLen() const override;
    std::ostream &insert(std::ostream &os) const override;

    IPAddress::ptr broadcastAddress(uint32_t prefix_len) override;
    IPAddress::ptr networkAddress(uint32_t prefix_len) override;
    IPAddress::ptr subnetMask(uint32_t prefix_len) override;
    uint32_t getPort() const override;
    void setPort(uint16_t v) override;

private:
    sockaddr_in m_addr;
};

/**
 * @brief IPv6地址
 */
class IPv6Address : public IPAddress {
public:
    typedef std::shared_ptr<IPv6Address> ptr;
    /**
     * @brief 通过IPv6地址字符串构造IPv6Address
     * @param[in] address IPv6地址字符串
     * @param[in] port 端口号
     */
    static IPv6Address::ptr Create(const char *address, uint16_t port = 0);

    /**
     * @brief 无参构造函数
     */
    IPv6Address();

    /**
     * @brief 通过sockaddr_in6构造IPv6Address
     * @param[in] address sockaddr_in6结构体
     */
    IPv6Address(const sockaddr_in6 &address);

    /**
     * @brief 通过IPv6二进制地址构造IPv6Address
     * @param[in] address IPv6二进制地址
     */
    IPv6Address(const uint8_t address[16], uint16_t port = 0);

    const sockaddr *getAddr() const override;
    sockaddr *getAddr() override;
    socklen_t getAddrLen() const override;
    std::ostream &insert(std::ostream &os) const override;

    IPAddress::ptr broadcastAddress(uint32_t prefix_len) override;
    IPAddress::ptr networkAddress(uint32_t prefix_len) override;
    IPAddress::ptr subnetMask(uint32_t prefix_len) override;
    uint32_t getPort() const override;
    void setPort(uint16_t v) override;

private:
    sockaddr_in6 m_addr;
};

/**
 * @brief UnixSocket地址
 */
class UnixAddress : public Address {
public:
    typedef std::shared_ptr<UnixAddress> ptr;

    /**
     * @brief 无参构造函数
     */
    UnixAddress();

    /**
     * @brief 通过路径构造UnixAddress
     * @param[in] path UnixSocket路径(长度小于UNIX_PATH_MAX)
     */
    UnixAddress(const std::string &path);

    const sockaddr *getAddr() const override;
    sockaddr *getAddr() override;
    socklen_t getAddrLen() const override;
    void setAddrLen(uint32_t v);
    std::string getPath() const;
    std::ostream &insert(std::ostream &os) const override;

private:
    sockaddr_un m_addr;
    socklen_t m_length;
};

/**
 * @brief 未知地址
 */
class UnknownAddress : public Address {
public:
    typedef std::shared_ptr<UnknownAddress> ptr;
    UnknownAddress(int family);
    UnknownAddress(const sockaddr &addr);
    const sockaddr *getAddr() const override;
    sockaddr *getAddr() override;
    socklen_t getAddrLen() const override;
    std::ostream &insert(std::ostream &os) const override;

private:
    sockaddr m_addr;
};

/**
 * @brief 流式输出Address
 */
std::ostream &operator<<(std::ostream &os, const Address &addr);

}

#endif

address.cc

#include "address.h"
#include "log.h"
#include <sstream>
#include <netdb.h>
#include <ifaddrs.h>
#include <stddef.h>

#include "endian.h"

namespace sylar {

static sylar::Logger::ptr g_logger = SYLAR_LOG_NAME("system");

//根据子网掩码位数,计算子网掩码对应的十进制数
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) {
        value &= value - 1;
    }
    return result;
}

//查找本机所有地址信息
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;
}

//查找本机所有IP地址信息
IPAddress::ptr Address::LookupAnyIPAddress(const std::string &host,
                                           int family, int type, int protocol) {
    std::vector<Address::ptr> result;
    if (Lookup(result, host, family, type, protocol)) {
		//根据强制转换是否成功来筛选IP地址信息
        for (auto &i : result) {
            IPAddress::ptr v = std::dynamic_pointer_cast<IPAddress>(i);
            if (v) {
                return v;
            }
        }
    }
    return nullptr;
}

// 查找本机地址相关信息(这是核心代码请详细阅读!!!)
// 首先这里的host参数有以下几种情况:
// 1.【IPv6有端口】,如:[FC00:0000:130F:0000:0000:09C0:876A:130B]:8080
// 2.【IPv6无端口】,如:FC00:0000:130F:0000:0000:09C0:876A:130B
// 3.【IPv4有端口】,如:192.168.0.1:8080
// 4.【IPv4无端口】,如:192.168.0.1
bool Address::Lookup(std::vector<Address::ptr> &result, const std::string &host,
                     int family, int type, int protocol) {
    addrinfo hints, *results, *next;
    
    hints.ai_flags     = 0;				// 地址信息标志
    hints.ai_family    = family;		// 地址族(AF_INET, AF_INET6, AF_UNSPEC)
    hints.ai_socktype  = type;			// 套接字类型(SOCK_STREAM, SOCK_DGRAM)
    hints.ai_protocol  = protocol;		// 协议号(IPPROTO_TCP, IPPROTO_UDP),或0表示任意协议
    hints.ai_addrlen   = 0;				// 地址长度
    hints.ai_canonname = NULL;			// 规范名字(主机名或服务名)
    hints.ai_addr      = NULL;			// 网络地址结构指针
    hints.ai_next      = NULL;			// 指向下一个addrinfo结构的指针
	
	// IP地址
    std::string node;
    // 对应端口
    const char *service = NULL;

    // 检查是否是指定端口的IPv6协议 
    // 如:[FC00:0000:130F:0000:0000:09C0:876A:130B]:8080
    // 如果host非空且第一个是符号 '[',证明有可能是带端口的IPv6
    if (!host.empty() && host[0] == '[') {
    	// 查找出符号 ']' 的指针 由于第一个字符已经确定是 '[' 了,所以在memchr中可以排除掉
        const char *endipv6 = (const char *)memchr(host.c_str() + 1, ']', host.size() - 1);
        if (endipv6) {
            // 判断字符 ']' 的下一位是否是字符 ':'
            if (*(endipv6 + 1) == ':') {
            	// 如果是字符 ':' 那么端口号的起始地址就是 endipv6 + 2 也就是字符 ']' 后的第二个开始到最后
                service = endipv6 + 2;
            }
            // 将IP地址部分截取,此时node就是 FC00:0000:130F:0000:0000:09C0:876A:130B
            node = host.substr(1, endipv6 - host.c_str() - 1);
        }
    }

    // 检查IP地址是否为空,为空证明当前host并不是【IPv6有端口】的模式
    if (node.empty()) {
    	// 查找第一个字符 ':' 因为IPv4有端口模式是根据 ':' 来分隔 IP:端口 的
        service = (const char *)memchr(host.c_str(), ':', host.size());
        // 判断是否存在字符 ':'
        if (service) {
        	// 判断是否只有一个字符 ':',如果只有一个,则证明是【IPv4有端口】模式,否则是【IPv6无端口】模式
            if (!memchr(service + 1, ':', host.c_str() + host.size() - service - 1)) {
            	// 确定是 【IPv4有端口】模式 如:192.168.0.1:8080
            	// 提取node 192.168.0.1
                node = host.substr(0, service - host.c_str());
                // 提取端口起始地址是 ':'的后一位开始到最后 即 8080
                ++service;
            }
        }
    }
	// 如果到此 node 还未提取出来,那么证明host只有以下两种模式的可能:
	// 1.host是 【IPv6无端口】 如:FC00:0000:130F:0000:0000:09C0:876A:130B
	// 2.host是 【IPv4无端口】 如:192.168.0.1
    if (node.empty()) {
        node = host;
    }
    
    // getaddrinfo函数根据给定的主机名和服务名,返回一个struct addrinfo结构链表
    // 每个struct addrinfo结构都包含一个互联网地址。  
	int error = getaddrinfo(node.c_str(), service, &hints, &results);
    if (error) {
        SYLAR_LOG_DEBUG(g_logger) << "Address::Lookup getaddress(" << host << ", "
                                  << family << ", " << type << ") err=" << error << " errstr="
                                  << gai_strerror(error);
        return false;
    }
	
	// 遍历互联网地址链表
    next = results;
    while (next) {
    	// 将互联网地址链表拆平结构,存储到vector中便于后续操作
        result.push_back(Create(next->ai_addr, (socklen_t)next->ai_addrlen));
        //一个ip/端口可以对应多种接字类型,比如SOCK_STREAM, SOCK_DGRAM, SOCK_RAW,所以这里会返回重复的结果
        SYLAR_LOG_DEBUG(g_logger) << "family:" << next->ai_family << ", sock type:" << next->ai_socktype;
        next = next->ai_next;
    }
	
	// 释放链表的内存空间
    freeaddrinfo(results);
    return !result.empty();
}

// 获取本机互联网地址信息
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_DEBUG(g_logger) << "Address::GetInterfaceAddresses getifaddrs "
                                     " err="
                                  << errno << " errstr=" << strerror(errno);
        return false;
    }

    try {
        for (next = results; next; next = next->ifa_next) {
            Address::ptr addr;
            uint32_t prefix_len = ~0u;
            if (family != AF_UNSPEC && family != next->ifa_addr->sa_family) {
                continue;
            }
            switch (next->ifa_addr->sa_family) {
            case AF_INET: {
                addr             = Create(next->ifa_addr, sizeof(sockaddr_in));
                uint32_t netmask = ((sockaddr_in *)next->ifa_netmask)->sin_addr.s_addr;
                prefix_len       = CountBytes(netmask);
            } break;
            case AF_INET6: {
                addr              = Create(next->ifa_addr, sizeof(sockaddr_in6));
                in6_addr &netmask = ((sockaddr_in6 *)next->ifa_netmask)->sin6_addr;
                prefix_len        = 0;
                for (int i = 0; i < 16; ++i) {
                    prefix_len += CountBytes(netmask.s6_addr[i]);
                }
            } break;
            default:
                break;
            }

            if (addr) {
                result.insert(std::make_pair(next->ifa_name,
                                             std::make_pair(addr, prefix_len)));
            }
        }
    } catch (...) {
        SYLAR_LOG_ERROR(g_logger) << "Address::GetInterfaceAddresses exception";
        freeifaddrs(results);
        return false;
    }
    freeifaddrs(results);
    return !result.empty();
}

bool Address::GetInterfaceAddresses(std::vector<std::pair<Address::ptr, uint32_t>> &result, const std::string &iface, int family) {
    if (iface.empty() || iface == "*") {
        if (family == AF_INET || family == AF_UNSPEC) {
            result.push_back(std::make_pair(Address::ptr(new IPv4Address()), 0u));
        }
        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;
    }

    auto its = results.equal_range(iface);
    for (; its.first != its.second; ++its.first) {
        result.push_back(its.first->second);
    }
    return !result.empty();
}

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

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

Address::ptr Address::Create(const sockaddr *addr, socklen_t addrlen) {
    if (addr == nullptr) {
        return nullptr;
    }

    Address::ptr result;
    switch (addr->sa_family) {
    case AF_INET:
        result.reset(new IPv4Address(*(const sockaddr_in *)addr));
        break;
    case AF_INET6:
        result.reset(new IPv6Address(*(const sockaddr_in6 *)addr));
        break;
    default:
        result.reset(new UnknownAddress(*addr));
        break;
    }
    return result;
}

bool Address::operator<(const Address &rhs) const {
    socklen_t minlen = std::min(getAddrLen(), rhs.getAddrLen());
    int result       = memcmp(getAddr(), rhs.getAddr(), minlen);
    if (result < 0) {
        return true;
    } else if (result > 0) {
        return false;
    } else if (getAddrLen() < rhs.getAddrLen()) {
        return true;
    }
    return false;
}

bool Address::operator==(const Address &rhs) const {
    return getAddrLen() == rhs.getAddrLen() && memcmp(getAddr(), rhs.getAddr(), getAddrLen()) == 0;
}

bool Address::operator!=(const Address &rhs) const {
    return !(*this == rhs);
}

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

    hints.ai_flags  = AI_NUMERICHOST;
    hints.ai_family = AF_UNSPEC;

    int error = getaddrinfo(address, NULL, &hints, &results);
    if (error) {
        SYLAR_LOG_DEBUG(g_logger) << "IPAddress::Create(" << address
                                  << ", " << port << ") error=" << error
                                  << " errno=" << errno << " errstr=" << strerror(errno);
        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;
    }
}

IPv4Address::ptr IPv4Address::Create(const char *address, uint16_t port) {
    IPv4Address::ptr rt(new IPv4Address);
    rt->m_addr.sin_port = byteswapOnLittleEndian(port);
    int result          = inet_pton(AF_INET, address, &rt->m_addr.sin_addr);
    if (result <= 0) {
        SYLAR_LOG_DEBUG(g_logger) << "IPv4Address::Create(" << address << ", "
                                  << port << ") rt=" << result << " errno=" << errno
                                  << " errstr=" << strerror(errno);
        return nullptr;
    }
    return rt;
}

IPv4Address::IPv4Address(const sockaddr_in &address) {
    m_addr = address;
}

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

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

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

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

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;
}

IPAddress::ptr IPv4Address::broadcastAddress(uint32_t prefix_len) {
    if (prefix_len > 32) {
        return nullptr;
    }

    sockaddr_in baddr(m_addr);
    baddr.sin_addr.s_addr |= byteswapOnLittleEndian(
        CreateMask<uint32_t>(prefix_len));
    return IPv4Address::ptr(new IPv4Address(baddr));
}

IPAddress::ptr IPv4Address::networkAddress(uint32_t prefix_len) {
    if (prefix_len > 32) {
        return nullptr;
    }

    sockaddr_in baddr(m_addr);
    baddr.sin_addr.s_addr &= byteswapOnLittleEndian(
        ~CreateMask<uint32_t>(prefix_len));
    return IPv4Address::ptr(new IPv4Address(baddr));
}

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

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

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

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);
    if (result <= 0) {
        SYLAR_LOG_DEBUG(g_logger) << "IPv6Address::Create(" << address << ", "
                                  << port << ") rt=" << result << " errno=" << errno
                                  << " errstr=" << strerror(errno);
        return nullptr;
    }
    return rt;
}

IPv6Address::IPv6Address() {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sin6_family = AF_INET6;
}

IPv6Address::IPv6Address(const sockaddr_in6 &address) {
    m_addr = address;
}

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.s6_addr, address, 16);
}

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

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

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

std::ostream &IPv6Address::insert(std::ostream &os) const {
    os << "[";
    uint16_t *addr  = (uint16_t *)m_addr.sin6_addr.s6_addr;
    bool used_zeros = false;
    for (size_t i = 0; i < 8; ++i) {
        if (addr[i] == 0 && !used_zeros) {
            continue;
        }
        if (i && addr[i - 1] == 0 && !used_zeros) {
            os << ":";
            used_zeros = true;
        }
        if (i) {
            os << ":";
        }
        os << std::hex << (int)byteswapOnLittleEndian(addr[i]) << std::dec;
    }

    if (!used_zeros && addr[7] == 0) {
        os << "::";
    }

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

IPAddress::ptr IPv6Address::broadcastAddress(uint32_t prefix_len) {
    sockaddr_in6 baddr(m_addr);
    baddr.sin6_addr.s6_addr[prefix_len / 8] |=
        CreateMask<uint8_t>(prefix_len % 8);
    for (int i = prefix_len / 8 + 1; i < 16; ++i) {
        baddr.sin6_addr.s6_addr[i] = 0xff;
    }
    return IPv6Address::ptr(new IPv6Address(baddr));
}

IPAddress::ptr IPv6Address::networkAddress(uint32_t prefix_len) {
    sockaddr_in6 baddr(m_addr);
    baddr.sin6_addr.s6_addr[prefix_len / 8] &=
        CreateMask<uint8_t>(prefix_len % 8);
    for (int i = prefix_len / 8 + 1; i < 16; ++i) {
        baddr.sin6_addr.s6_addr[i] = 0x00;
    }
    return IPv6Address::ptr(new IPv6Address(baddr));
}

IPAddress::ptr IPv6Address::subnetMask(uint32_t prefix_len) {
    sockaddr_in6 subnet;
    memset(&subnet, 0, sizeof(subnet));
    subnet.sin6_family = AF_INET6;
    subnet.sin6_addr.s6_addr[prefix_len / 8] =
        ~CreateMask<uint8_t>(prefix_len % 8);

    for (uint32_t i = 0; i < prefix_len / 8; ++i) {
        subnet.sin6_addr.s6_addr[i] = 0xff;
    }
    return IPv6Address::ptr(new IPv6Address(subnet));
}

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

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

static const size_t MAX_PATH_LEN = sizeof(((sockaddr_un *)0)->sun_path) - 1;

UnixAddress::UnixAddress() {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sun_family = AF_UNIX;
    m_length          = offsetof(sockaddr_un, sun_path) + MAX_PATH_LEN;
}

UnixAddress::UnixAddress(const std::string &path) {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sun_family = AF_UNIX;
    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");
    }
    memcpy(m_addr.sun_path, path.c_str(), m_length);
    m_length += offsetof(sockaddr_un, sun_path);
}

void UnixAddress::setAddrLen(uint32_t v) {
    m_length = v;
}

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

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

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

std::string UnixAddress::getPath() const {
    std::stringstream ss;
    if (m_length > offsetof(sockaddr_un, sun_path) && m_addr.sun_path[0] == '\0') {
        ss << "\\0" << std::string(m_addr.sun_path + 1, m_length - offsetof(sockaddr_un, sun_path) - 1);
    } else {
        ss << m_addr.sun_path;
    }
    return ss.str();
}

std::ostream &UnixAddress::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;
}

UnknownAddress::UnknownAddress(int family) {
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sa_family = family;
}

UnknownAddress::UnknownAddress(const sockaddr &addr) {
    m_addr = addr;
}

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

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

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

std::ostream &UnknownAddress::insert(std::ostream &os) const {
    os << "[UnknownAddress family=" << m_addr.sa_family << "]";
    return os;
}

std::ostream &operator<<(std::ostream &os, const Address &addr) {
    return addr.insert(os);
}

}

由于最近白天比较忙,导致我写博客的频率变低了,在此警示自己,再忙也要坚持!!!

【最后求关注、点赞、转发】
QQ交流群:957100923
在这里插入图片描述

  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值