muduo源码解析20-inetaddress类

inetaddress类:

说明:

封装了一个套接字地址类,实现与IPV6和IPV4具体操作无关的一个类,用户只需要在定义时确定IPV4/IPV6即可,所提供的操作与具体的IPV4/IPV6协议无关。

内部用共同体union {sockaddr_in6 m_addr6 ;  sockaddr_in m_addr}实现,因此sizeof(inetaddress)==sizeof(sockaddr_in6) 

构造函数要求指定创建的是IPV6还是IPV4地址,用来确定使用m_addr6还是m_addr
构造函数意义就是为了实现内部m_addr的初始化,也就是设置三个成员port,addr和family

内部还提供了一些get IP,port,family,sockaddr*等一些函数用于获取信息
内部实现基本用sockets命名空间中的一些封装来实现

成员变量:

private:
    union
    {
        //size分别是多少,待会测一下
        //sockaddr:16,sockaddr_in:16,sockaddr_in6:28
        struct sockaddr_in m_addr;
        struct sockaddr_in6 m_addr6;
    };

成员函数:

public:
    //所有的构造函数都完成m_addr6/m_addr的初始化,也就是设置port,addr,family
    //explicit禁止隐式类型转换
    explicit inetaddress(uint16_t port=0,bool loopbackOnly=false,bool ipv6=false);

    inetaddress(string ip,uint16_t port,bool ipv6=false);

    //构造函数,IPV4地址
    explicit inetaddress(const struct sockaddr_in& addr)
        :m_addr(addr)
    {}

    //构造函数,IPV6地址
    explicit inetaddress(const struct sockaddr_in6& addr)
        :m_addr6(addr)
    {}

    //返回地址族,IP,IP:port,port,sockaddr*信息
    sa_family_t family() const {return m_addr.sin_family;}
    string toIp() const;
    string toIpPort() const;
    uint16_t toPort() const;

    const struct sockaddr* getSockAddr() const
    {
        return sockets::sockaddr_cast(&m_addr6);
    }

    //设置IPV6 m_addr
    void setSockAddrInet6(const struct sockaddr_in6& addr6)
    {
        m_addr6=addr6;
    }
    //获取m_addr.sin_addr.s_addr,即IP地址网络字节序
    uint32_t ipNetEndian() const;
    //获取端口号的网络字节序
    uint16_t portEntEndian() const{return m_addr.sin_port;}

    //线程安全,完成主机名到IP地址的转换,不改变端口号和地址族
    //内部使用gethostbyname_r()实现
    static bool resolve(string hostname,inetaddress* result);

    //设置 IPV6 ScopeId
    void setScopeId(uint32_t scope_id);

inet_address.h:

#ifndef INETADDRESS_H
#define INETADDRESS_H

#include"base/copyable.h"
#include<netinet/in.h>

#include"base/types.h"


namespace mymuduo {

namespace net {

//声明sockets::sockaddr_cast函数
namespace sockets{
const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr);
}//namespace sockets

class inetaddress:copyable
{
public:
    //所有的构造函数都完成m_addr6/m_addr的初始化,也就是设置port,addr,family
    //explicit禁止隐式类型转换
    explicit inetaddress(uint16_t port=0,bool loopbackOnly=false,bool ipv6=false);

    inetaddress(string ip,uint16_t port,bool ipv6=false);

    //构造函数,IPV4地址
    explicit inetaddress(const struct sockaddr_in& addr)
        :m_addr(addr)
    {}

    //构造函数,IPV6地址
    explicit inetaddress(const struct sockaddr_in6& addr)
        :m_addr6(addr)
    {}

    //返回地址族,IP,IP:port,port,sockaddr*信息
    sa_family_t family() const {return m_addr.sin_family;}
    string toIp() const;
    string toIpPort() const;
    uint16_t toPort() const;

    const struct sockaddr* getSockAddr() const
    {
        return sockets::sockaddr_cast(&m_addr6);
    }

    //设置IPV6 m_addr
    void setSockAddrInet6(const struct sockaddr_in6& addr6)
    {
        m_addr6=addr6;
    }
    //获取m_addr.sin_addr.s_addr,即IP地址网络字节序
    uint32_t ipNetEndian() const;
    //获取端口号的网络字节序
    uint16_t portEntEndian() const{return m_addr.sin_port;}

    //线程安全,完成主机名到IP地址的转换,不改变端口号和地址族
    //内部使用gethostbyname_r()实现
    static bool resolve(string hostname,inetaddress* result);

    //设置 IPV6 ScopeId
    void setScopeId(uint32_t scope_id);
private:
    union
    {
        //size分别是多少,待会测一下
        //sockaddr:16,sockaddr_in:16,sockaddr_in6:28
        struct sockaddr_in m_addr;
        struct sockaddr_in6 m_addr6;
    };

};

}//namespace net

}//namespace mymuduo


#endif // INETADDRESS_H

 

inet_address.cpp:

#include "inetaddress.h"

#include"base/logging.h"
#include"net/socketsops.h"
#include"net/endian.h"

#include<netdb.h>

//变量(代码)级:指定某个变量警告
// INADDR_ANY use (type)value casting.
#pragma GCC diagnostic ignored "-Wold-style-cast"
static const in_addr_t kInaddrAny = INADDR_ANY;
static const in_addr_t kInaddrLoopback = INADDR_LOOPBACK;
#pragma GCC diagnostic error "-Wold-style-cast"
// sockaddr_in,in_addr_t,sockaddr_in6结构
//     /* Structure describing an Internet socket address.  */
//     struct sockaddr_in {
//         sa_family_t    sin_family; /* address family: AF_INET */
//         uint16_t       sin_port;   /* port in network byte order */
//         struct in_addr sin_addr;   /* internet address */
//     };

//     /* Internet address. */
//     typedef uint32_t in_addr_t;
//     struct in_addr {
//         in_addr_t       s_addr;     /* address in network byte order */
//     };

//     struct sockaddr_in6 {
//         sa_family_t     sin6_family;   /* address family: AF_INET6 */
//         uint16_t        sin6_port;     /* port in network byte order */
//         uint32_t        sin6_flowinfo; /* IPv6 flow information */
//         struct in6_addr sin6_addr;     /* IPv6 address */
//         uint32_t        sin6_scope_id; /* IPv6 scope-id */
//     };


namespace mymuduo {

namespace net{

//静态编译时断言
static_assert(sizeof(inetaddress) == sizeof(struct sockaddr_in6),
"InetAddress is same size as sockaddr_in6");
static_assert(offsetof(sockaddr_in, sin_family) == 0, "sin_family offset 0");
static_assert(offsetof(sockaddr_in6, sin6_family) == 0, "sin6_family offset 0");
static_assert(offsetof(sockaddr_in, sin_port) == 2, "sin_port offset 2");
static_assert(offsetof(sockaddr_in6, sin6_port) == 2, "sin6_port offset 2");


//explicit禁止隐式类型转换
//构造函数,利用默认本地IP地址初始化m_addr6/m_addr
inetaddress::inetaddress(uint16_t port,bool loopbackOnly,bool ipv6)
{
    static_assert (offsetof(inetaddress,m_addr6)==0,"m_addr6 offset 0");
    static_assert(offsetof(inetaddress,m_addr)==0,"m_addr offset 0");
    //判断是否是IPV6
    if(ipv6)
    {
        memZero(&m_addr6,sizeof(m_addr6));
        m_addr6.sin6_family=AF_INET6;
        m_addr6.sin6_port=sockets::hostToNetwork16(port);
        //是否是本地ip绑定,127.0.0.1
        struct in6_addr ip=loopbackOnly?in6addr_loopback:in6addr_any;
        m_addr6.sin6_addr=ip;
    }else
    {
        memZero(&m_addr,sizeof(m_addr));
        m_addr.sin_family=AF_INET;
        m_addr.sin_port=sockets::hostToNetwork16(port);
        //是否绑定本地
        in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny;
        m_addr.sin_addr.s_addr=sockets::hostToNetwork32(ip);
    }
}

//构造函数,利用给定IP地址初始化m_addr6/m_addr
inetaddress::inetaddress(string ip,uint16_t port,bool ipv6)
{
    if(ipv6)
    {
        memZero(&m_addr6,sizeof(m_addr6));
        sockets::fromIpPort(ip.data(),port,&m_addr6);
    }else
    {
        memZero(&m_addr,sizeof(m_addr));
        sockets::fromIpPort(ip.data(),port,&m_addr);
    }
}

//返回IP地址字符串
string inetaddress::toIp() const
{
    char buf[64]={0};
    sockets::toIp(buf,sizeof(buf),getSockAddr());
    return buf;
}
//返回IP:port字符串
string inetaddress::toIpPort() const
{
    char buf[64]={0};
    sockets::toIpPort(buf,sizeof(buf),getSockAddr());
    return buf;
}

uint16_t inetaddress::toPort() const
{
    return sockets::networkToHost16(portEntEndian());
}

static __thread char t_resolveBuffer[64*1024];

//返回sockaddr的网络字节序
uint32_t inetaddress::ipNetEndian() const
{
    assert(family()==AF_INET);
    return m_addr.sin_addr.s_addr;
}

//线程安全,完成主机名到IP地址的转换,不改变端口号和地址族
bool inetaddress::resolve(string hostname,inetaddress* out)
{
    assert(out != NULL);
    struct hostent hent;
    struct hostent* he = NULL;
    int herrno = 0;
    memZero(&hent, sizeof(hent));

    int ret = gethostbyname_r(hostname.c_str(), &hent, t_resolveBuffer, sizeof t_resolveBuffer, &he, &herrno);
    if (ret == 0 && he != NULL)
    {
        assert(he->h_addrtype == AF_INET && he->h_length == sizeof(uint32_t));
        out->m_addr.sin_addr = *reinterpret_cast<struct in_addr*>(he->h_addr);
        return true;
    }
    else
    {
        if (ret)
        {
            LOG_SYSERR << "InetAddress::resolve";
        }
        return false;
    }

}

//设置 IPV6 ScopeId
void inetaddress::setScopeId(uint32_t scope_id)
{
    if(family()==AF_INET6)
        m_addr6.sin6_scope_id=scope_id;
}


}//namespace net

}//namespace mymuduo

测试:

#include"base/thread.h"
#include"net/inetaddress.h"

#include<iostream>
using namespace mymuduo::net;

int main()
{

    inetaddress addr4_1(12306,true);
    std::cout<<addr4_1.toIpPort()<<std::endl;
    //用addr4_1的m_addr去构造addr4_2
    inetaddress addr4_2(*(reinterpret_cast<const sockaddr_in*>(addr4_1.getSockAddr())));
    std::cout<<addr4_2.toIpPort()<<std::endl;

    inetaddress addr4_3("192.168.1.103",12345);
    std::cout<<addr4_3.toIpPort()<<std::endl;

}

打印结果:

127.0.0.1:12306
127.0.0.1:12306
192.168.1.103:12345

 

posted @ 2020-08-28 16:40  WoodInEast  阅读(454)  评论(0)    收藏  举报