我是靠谱客的博主 殷勤项链,最近开发中收集的这篇文章主要介绍[源码阅读]——Sylar服务器框架:Address模块,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Address模块

    • address模块概述
    • address模块实现
    • 其他

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方法,其他的LookupAnyLookupAnyIPAddressGetInterfaceAddresses这些大多是基于其实现。

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等模块阅读之后感觉还有要补充的会再做补充。

最后

以上就是殷勤项链为你收集整理的[源码阅读]——Sylar服务器框架:Address模块的全部内容,希望文章能够帮你解决[源码阅读]——Sylar服务器框架:Address模块所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部