muduo网络库核心代码阅读(Timestamp,InetAddress)(2)

TimeStamp

TiemStamp类是muduo中的时间戳类,用于获取当前时间的格式化字符串。

成员变量

int64_t microSecondsSinceEpoch_;

TimeStamp类只有一个成员变量microSecondsSinceEpoch_,它保存了从1970年1月1日00:00:00 UTC到当前时间的微秒数。由于只有一个int64_t类型的成员变量,他的值传递非常高效。而且该类本身无法修改(没有提供修改成员变量的接口),并只能通过值传递(继承了copyable)。

核心方法

now

now()是TimeStamp类的静态方法,用于获取当前时间的TimeStamp对象。

// TimeStamp.h
static Timestamp now();

// TimeStamp.cc
Timestamp Timestamp::now()
{
    /*timeval结构体定义: 
        struct timeval
        {
            long tv_sec;   //秒数
            long tv_usec;    //微妙数
        };
    */
    struct timeval tv;
    gettimeofday(&tv, NULL);     //获取当前时间(从1970年1月1日00:00:00 UTC到当前时间的微秒数)
    int64_t seconds = tv.tv_sec;
    return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec);    //获取总微妙数
}
toString

toString()是TimeStamp类的成员方法,用于获取当前时间的格式化字符串,形式为seconds.microseconds。

string Timestamp::toString() const
{
    char buf[32] = {0};
    int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond;         //获取秒数
    int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;      //获取微妙数
    snprintf(buf, sizeof(buf), "%" PRId64 ".%06" PRId64 "", seconds, microseconds);   //拼接,PRId64是用于格式化 int64_t 类型整数的宏
    return buf;
}
toFormattedString

toFormattedString()是TimeStamp类的成员方法,用于获取当前时间的格式化字符串,形式为Ymd H:M:S seconds.microseconds。

string Timestamp::toFormattedString(bool showMicroseconds) const
{
    char buf[64] = {0};
    time_t seconds = static_cast<time_t>(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);
    struct tm tm_time;
    gmtime_r(&seconds, &tm_time);

    if (showMicroseconds)       //判断是否显示微秒(默认显示)
    {
        int microseconds = static_cast<int>(microSecondsSinceEpoch_ % kMicroSecondsPerSecond);
        snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d",
                tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
                tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec,
                microseconds);
    }
    else
    {
        snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d",
                tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
                tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
    }
    return buf;
}
实例
#include <muduo/base/Timestamp.h>
#include <iostream>

int main(){
    std::cout << muduo::Timestamp::now().toString() << std::endl;
    std::cout << muduo::Timestamp::now().toFormattedString() << std::endl;
    return 0;
}
$ g++ test.cpp -o test -lmuduo_base
$ ./test

输出:
1737375966.121036
20250120 12:26:06.121244

InetAddress

InetAddress类是muduo中的网络地址类,用于表示IP地址和端口号。

类设计

InetAddress本身不是pod类型(plain old data),但他旨在设计为一个类似pod的接口类。

/// This is an POD interface class.
class InetAddress : public muduo::copyable
{
    //...
};

成员变量

成员变量为一个联合体,支持IPV4地址和IPV6地址,大小为IPV6地址大小。

union
{
    struct sockaddr_in addr_;
    struct sockaddr_in6 addr6_;
};

构造函数

/// Constructs an endpoint with given port number.
/// Mostly used in TcpServer listening.
explicit InetAddress(uint16_t port = 0, bool loopbackOnly = false, bool ipv6 = false);

/// Constructs an endpoint with given ip and port.
/// @c ip should be "1.2.3.4"
InetAddress(StringArg ip, uint16_t port, bool ipv6 = false);

/// InetAddress只有一个包含sockaddr_in和sockaddr_in6的联合体,所以通过以下两种构造函数,可以很方便的实现地址的转换
/// Constructs an endpoint with given struct @c sockaddr_in
/// Mostly used when accepting new connections
explicit InetAddress(const struct sockaddr_in& addr)
    : addr_(addr)
{ }

explicit InetAddress(const struct sockaddr_in6& addr)
    : addr6_(addr)
{ }


//实现
    InetAddress::InetAddress(uint16_t portArg, bool loopbackOnly, bool ipv6)
{
static_assert(offsetof(InetAddress, addr6_) == 0, "addr6_ offset 0");
static_assert(offsetof(InetAddress, addr_) == 0, "addr_ offset 0");
if (ipv6)
{
    memZero(&addr6_, sizeof addr6_);   //清空addr6_
    addr6_.sin6_family = AF_INET6;
    in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any;
    addr6_.sin6_addr = ip;
    addr6_.sin6_port = sockets::hostToNetwork16(portArg);  //转换端口号为网络字节序
}
else
{
    memZero(&addr_, sizeof addr_);
    addr_.sin_family = AF_INET;
    in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny;
    addr_.sin_addr.s_addr = sockets::hostToNetwork32(ip);  //转换IP地址为网络字节序
    addr_.sin_port = sockets::hostToNetwork16(portArg); //转换端口号为网络字节序
}
}

核心方法

InetAddress提供了一系列接口来获取地址和端口号。sockets命名空间中定义了一系列关于socket的操作函数,方便操作。

sa_family_t family() const { return addr_.sin_family; }
string toIp() const;
string toIpPort() const;
uint16_t port() const;

//实现
string InetAddress::toIpPort() const
{
    char buf[64] = "";
    sockets::toIpPort(buf, sizeof buf, getSockAddr());
    return buf;
}

string InetAddress::toIp() const
{
    char buf[64] = "";
    sockets::toIp(buf, sizeof buf, getSockAddr());
    return buf;
}

uint16_t InetAddress::port() const
{
    return sockets::networkToHost16(portNetEndian());
}
posted @   xiaodao0036  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示