muduo 是一个基于 Reactor 模式的现代 C++ 网络库,作者陈硕。它采用非阻塞 IO 模型,基于事件驱动和回调,原生支持多核多线程,适合编写 Linux 服务端多线程网络应用程序。
muduo网络库的核心代码只有数千行,在网络编程技术学习的进阶阶段,muduo是一个非常值得学习的开源库。目前我也是刚刚开始学习这个网络库的源码,希望将这个学习过程记录下来。这个网络库的源码已经发布在GitHub上,可以点击这里阅读。目前Github上这份源码已经被作者用c++11重写,我学习的版本是没有使用c++11版本的。不过二者大同小异,核心思想是没有变化的。我的代码库在这里。
muduo网络库的核心代码分为base库和net库,在今后的博客中首先介绍base库的复现,继而介绍net库的复现,最后介绍几个muduo库的几个应用。
Timestamp.h顾名思义,封装了关于时间的操作。在TimeStamp.h中封装了类Timestamp,这个类只有一个私有变量microSecondsSinceEpoch_,表示距离1970年1月1日0:00的毫秒数。这个类还封装了一些函数,基本都是围绕microSecondsSinceEpoch_做一些操作,其中toString和toFormattedString()比较值得注意。
首先来看一下toString()函数的代码:
string Timestamp::toString() const{
char buf[32];
int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond;
int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;
snprintf(buf,sizeof(buf)-1,"%" PRId64 ".%06" PRId64 "",seconds,microseconds);
return buf;
}
这个函数的作用是将microSecondsSinceEpoch_转化为秒数和微秒数的组合,然后使用snprintf转成一个符合格式的字符串。
snprintf函数原型:int snprintf(char* dest_str,size_t size,const char* format,...);
参数含义为
char *dest:传出字符串
size_t size:拷贝字符数,最大sizeof(dest)-1
后面的变参为具体的格式
这里PRId64是一种跨平台的书写方式,主要是为了同时支持32位和64位操作系统。PRId64表示64位整数,在32位系统中表示long long int,在64位系统中表示long int。相当于:
printf("%" "ld" "\n", value); //64bit OS
printf("%" "lld" "\n", value); //32bit OS
首先看一下toFormattedString() 函数的代码。
string Timestamp::toFormattedString() const
{
char buf[32];
time_t seconds = static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);
int microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;
struct tm tm_time;
gmtime_r(&seconds,&tm_time);
snprintf(buf,sizeof(buf)-1,"%04d%02d%2d:%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);
return buf;
}
这个函数的作用是将microSecondsSinceEpoch_转化为年月日分秒的字符串形式。这个功能借助于struct tm和gmtime函数。
struct tm结构体定义如下:
struct tm {
int tm_sec; /* 秒 – 取值区间为[0,59] */
int tm_min; /* 分 - 取值区间为[0,59] */
int tm_hour; /* 时 - 取值区间为[0,23] */
int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */
int tm_mon; /* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */
int tm_year; /* 年份,其值等于实际年份减去1900 */
int tm_wday; /* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 */
int tm_yday; /* 从每年的1月1日开始的天数 – 取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推 */
int tm_isdst; /* 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的时候,tm_isdst为0;不了解情况时,tm_isdst()为负。
long int tm_gmtoff; /*指定了日期变更线东面时区中UTC东部时区正秒数或UTC西部时区的负秒数*/
const char *tm_zone; /*当前时区的名字(与环境变量TZ有关)*/
};
localtime是把从1970-1-1零点零分到当前时间系统所偏移的秒数时间转换为UTC时间,将tm_time传出。