早在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.0 | 11111111 00000000 00000000 00000000 | 4278190080 |
9位子网掩码 | 255.128.0.0 | 11111111 10000000 00000000 00000000 | 4286578688 |
10位子网掩码 | 255.192.0.0 | 11111111 11000000 00000000 00000000 | 4290772992 |
11位子网掩码 | 255.224.0.0 | 11111111 11100000 00000000 00000000 | 4292870144 |
12位子网掩码 | 255.240.0.0 | 11111111 11110000 00000000 00000000 | 4293918720 |
13位子网掩码 | 255.248.0.0 | 11111111 11111000 00000000 00000000 | 4294443008 |
14位子网掩码 | 255.252.0.0 | 11111111 11111100 00000000 00000000 | 4294705152 |
15位子网掩码 | 255.254.0.0 | 11111111 11111110 00000000 00000000 | 4294836224 |
16位子网掩码 | 255.255.0.0 | 11111111 11111111 00000000 00000000 | 4294901760 |
17位子网掩码 | 255.255.128.0 | 11111111 11111111 10000000 00000000 | 4294934528 |
18位子网掩码 | 255.255.192.0 | 11111111 11111111 11000000 00000000 | 4294950912 |
19位子网掩码 | 255.255.224.0 | 11111111 11111111 11100000 00000000 | 4294959104 |
20位子网掩码 | 255.255.240.0 | 11111111 11111111 11110000 00000000 | 4294963200 |
21位子网掩码 | 255.255.248.0 | 11111111 11111111 11111000 00000000 | 4294965248 |
22位子网掩码 | 255.255.252.0 | 11111111 11111111 11111100 00000000 | 4294966272 |
23位子网掩码 | 255.255.254.0 | 11111111 11111111 11111110 00000000 | 4294966784 |
24位子网掩码 | 255.255.255.0 | 11111111 11111111 11111111 00000000 | 4294967040 |
25位子网掩码 | 255.255.255.128 | 11111111 11111111 11111111 10000000 | 4294967168 |
26位子网掩码 | 255.255.255.192 | 11111111 11111111 11111111 11000000 | 4294967232 |
27位子网掩码 | 255.255.255.224 | 11111111 11111111 11111111 11100000 | 4294967264 |
28位子网掩码 | 255.255.255.240 | 11111111 11111111 11111111 11110000 | 4294967280 |
29位子网掩码 | 255.255.255.248 | 11111111 11111111 11111111 11111000 | 4294967288 |
30位子网掩码 | 255.255.255.252 | 11111111 11111111 11111111 11111100 | 4294967292 |
31位子网掩码 | 255.255.255.254 | 11111111 11111111 11111111 11111110 | 4294967294 |
32位子网掩码 | 255.255.255.255 | 11111111 11111111 11111111 11111111 | 4294967295 |
假如我们得到十进制数,需要算出其子网掩码的位数,该怎么办呢?
我们先做个实验:
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非空且第一个是符号 '[',证明有可能是带端口的IPv6if (!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:130Bnode = 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.1node = 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.1if (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