[源码阅读]——Sylar服务器框架:Address模块

本文详细解读了Sylar框架中的Address模块,介绍了其在处理IPv4/IPv6/Unix网络地址方面的封装和接口实现,以及Lookup、Create等关键方法的工作原理。阅读难度降低,着重于功能实现和接口设计。
摘要由CSDN通过智能技术生成

address模块概述

  这一部分主要是为后面的网络模块进行服务了,其主要作用就针对IPv4、IPv6、Unix的网络地址进行一系列封装和方法的实现,通过统一的对外接口实现网络地址的相关查询等,方便了后续socket等模块的实现。
  本人感觉从这一模块开始,sylar的代码阅读难度就没有之前那么难了,更多的是功能的实现、接口的封装等,相比于IO协程调度、定时器等这些理解有难度的模块,可以说是简单了一些。

address模块实现

  从基类开始阅读吧就:

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

    // 通过sockaddr指针创建Address
    static Address::ptr Create(const sockaddr* addr, socklen_t addrlen);

    // 通过host地址返回对应条件的所有Address
    static bool Lookup(std::vector<Address::ptr>& result, const std::string& host, int family = AF_INET, int type = 0, int protocol = 0);
    // 通过host地址返回对应条件的任意Address
    static Address::ptr LookupAny(const std::string& host, int family = AF_INET, int type = 0, int protocol = 0);
    // 通过host地址返回对应条件的任意IPAddress
    static std::shared_ptr<IPAddress> LookupAnyIPAddress(const std::string& host, int family = AF_INET, int type = 0, int protocol = 0);

    // 返回本机所有网卡的<网卡名, 地址, 子网掩码位数>
    static bool GetInterfaceAddresses(std::multimap<std::string, std::pair<Address::ptr, uint32_t> >& result, int family = AF_INET);
    // 获取指定网卡的地址和子网掩码位数
    static bool GetInterfaceAddresses(std::vector<std::pair<Address::ptr, uint32_t> >&result ,const std::string& iface, int family = AF_INET);

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

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

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

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

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

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

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

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

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

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

  其中,主要的方法是Lookup方法和Create方法,其他的LookupAny\LookupAnyIPAddress\GetInterfaceAddresses这些大多是基于其实现。

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;
    hints.ai_socktype = type;
    hints.ai_protocol = protocol;
    hints.ai_addrlen = 0;
    hints.ai_canonname = NULL;
    hints.ai_addr = NULL;
    hints.ai_next = NULL;

    std::string node;
    const char* service = NULL;

    //检查 ipv6address serivce
    if(!host.empty() && host[0] == '[') {
        // void *memchr(const void *str, int c, size_t n)
        // 搜索参数str指向的字符串的前n个字节中第一次出现的字符c(unsigned char类型)。
        const char* endipv6 = (const char*)memchr(host.c_str() + 1, ']', host.size() - 1);
        if(endipv6) {
            //TODO check out of range
            if(*(endipv6 + 1) == ':') {
                service = endipv6 + 2;
            }
            node = host.substr(1, endipv6 - host.c_str() - 1);
        }
    }

    //检查 node serivce
    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;
            }
        }
    }

    if(node.empty()) {
        node = host;
    }
    // 处理名字到地址以及服务到端口这两种转换,返回的是一个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) {
        result.push_back(Create(next->ai_addr, (socklen_t)next->ai_addrlen));
        //SYLAR_LOG_INFO(g_logger) << ((sockaddr_in*)next->ai_addr)->sin_addr.s_addr;
        next = next->ai_next;
    }

    // 释放空间
    freeaddrinfo(results);
    return !result.empty();
}
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;
}

  随后便是IP地址的基类创建:

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

    /、 通过域名,IP,服务器名创建IPAddress
    static IPAddress::ptr Create(const char* address, uint16_t port = 0);

    // 获取该地址的广播地址
    virtual IPAddress::ptr broadcastAddress(uint32_t prefix_len) = 0;

    // 获取该地址的网段
    virtual IPAddress::ptr networdAddress(uint32_t prefix_len) = 0;

    // 获取子网掩码地址
    virtual IPAddress::ptr subnetMask(uint32_t prefix_len) = 0;

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

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

  其中

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

  剩下的就是几个子类的实现和具体方法的实现了

其他

  Address模块阅读起来并不算难,但是真的想掌握的话建议还是多看看源码,还有就是对一些系统方法要比较了解,感觉这一块就这样吧,如果后续结合socket等模块阅读之后感觉还有要补充的会再做补充。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

甄姬、巴豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值