1. 程式人生 > 實用技巧 >muduo原始碼解析20-inetaddress類

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