muduo 是一个基于 Reactor 模式的现代 C++ 网络库,作者陈硕。它采用非阻塞 IO 模型,基于事件驱动和回调,原生支持多核多线程,适合编写 Linux 服务端多线程网络应用程序。
muduo网络库的核心代码只有数千行,在网络编程技术学习的进阶阶段,muduo是一个非常值得学习的开源库。目前我也是刚刚开始学习这个网络库的源码,希望将这个学习过程记录下来。这个网络库的源码已经发布在GitHub上,可以点击这里阅读。目前Github上这份源码已经被作者用c++11重写,我学习的版本是没有使用c++11版本的。不过二者大同小异,核心思想是没有变化的。点这里可以看我的源代码,如果你对我之前的博客有兴趣,可以点击下面的连接:
muduo网络库源码复现笔记(一):base库的Timestamp.h
muduo网络库源码复现笔记(二):base库的Atomic.h
muduo网络库源码复现笔记(三):base库的Exception.h
muduo网络库源码复现笔记(四):base库的Thread.h和CurrentThread.h
muduo网络库源码复现笔记(五):base库的Mutex.h和Condition.h和CoutntDownLatch.h
muduo网络库源码复现笔记(六):base库的BlockingQueue.h和BoundedBlockingQueue.h
muduo网络库源码复现笔记(七):base库的ThreadPool.h
muduo网络库源码复现笔记(八):base库的Singleton.h
muduo网络库源码复现笔记(九):base库的ThreadLocalSingleton.h
muduo网络库源码复现笔记(十):base库的ThreadLocalSingleton.h
muduo使用了StringPiece.h,这是一个谷歌公开的一个头文件,这个文件封装了StringPiece类,这个类不涉及内存拷贝,实现了高效的字符串传递。比如有一个函数它的参数需要同时兼容std::string和const char*,我们一般是这么定义的:
void foo(const string& str);
如果传入很长一个const char*的话,会生成一个较大的string对象,开销比较大。如果你的目的仅仅是读取字符串的值,则可使用
void foo(const StringPiece& str)
通过这个方法可以减小开销。下面是这个类的关键要素的分析。
StringPiece有两个私有成员,第一个是const char型指针ptr_,用于帮助字符串的读取,字符串的实际内存与它无关。length_是目的字符串的长度。
const char* ptr_;
int length_;
正如前面所说,ptr_是一个const char型指针,所以字符串的实际内存与它无关,所以不会使用ptr_进行很复杂的操作,故StringPiece的成员函数都很简单。举一个栗子:
void remove_prefix(int n)
{
ptr_ += n;
length_ -= n;
}
这个函数是去除读取字符串的头n个字节,只需ptr向后移动,length减去相应的字节数即可。
类中使用了一个通过宏定义来实现重载的技巧值得学习一下,代码如下:
#define STRINGPIECE_BINARY_PREDICATE(cmp,auxcmp) \
bool operator cmp (const StringPiece& x) const { \
int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \
return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_))); \
}
STRINGPIECE_BINARY_PREDICATE(<, <);
STRINGPIECE_BINARY_PREDICATE(<=, <);
STRINGPIECE_BINARY_PREDICATE(>=, >);
STRINGPIECE_BINARY_PREDICATE(>, >);
#undef STRINGPIECE_BINARY_PREDICATE
通过宏定义,实现了StringPiece类<,<=,>,>=的比较,当然本质还是比较ptr_指向的字符串。宏定义中cmp就是我们想要进行操作的字符串,aux用于辅助比较。举例来说,如果我们有StringPiece str1(“abcz”),str2(“abcdef”),
std::cout << (str1 < str2) << std:: endl的结果如何呢?由于str1的length_小于str2的length_,那么r = 0;return后的语句里 r < 0不成立,r==0成立但二者length_不相等,所以返回false。其他操作也可如此类推,总之这一段代码技巧性很强。
StringPiece利用了traits和模板特化与偏特化能力,提升了性能。
template<> struct __type_traits {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
这个是比较高级的c++编程技巧,目前还不会,再深入之后学习来补。