构建自己的muduo库-1
构建自己的muduo库-1
由于muduo库的网络库原本使用了很多boost库的内容,所以我想手写自己的my muduo库,使用C++11特性去替换掉boost部分内容
构建项目建立CMake文件
项目根目录下CMakeLists内容
cmake_minimum_required(VERSION 2.5)
project(mymuduo)
# mymuduo最终编译成so动态库,设置动态库路径,放在根目录的lib文件夹下
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
# 设置调试信息 以及 启动C++11语言标准
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -std=c++11")
# 定义参与编译的源代码文件
aux_source_directory(. SRC_LIST)
# 编译生成动态库mymuduo
add_library(mymuduo SHARED ${SRC_LIST})
noncopyable的代码
muduo库里面很多class都继承了noncopyable,看看这个类的代码
noncopyable.h
namespace muduo
{
class noncopyable
{
public:
noncopyable(const noncopyable&) = delete;
void operator=(const noncopyable&) = delete;
protected:
noncopyable() = default;
~noncopyable() = default;
};
} // namespace muduo
让继承的类不可使用拷贝构造和赋值构造,这样可以让每个类都继承这个类,不用一一都写上禁止拷贝构造和禁止赋值操作。
模仿着写一下
#pragma once
// noncopyable被继承后,派生类对象可以正常的构造和析构,但是
// 派生类对象不可进行拷贝构造和赋值操作
class noncopyable{
public:
noncopyable(const noncopyable&)=delete;
noncopyable& operator=(const noncopyable&)=delete;
protected:
noncopyable()=default;
~noncopyable()=default;
};
Logger日志
分为Logger.h Logger.cc
日志等级
INFO, // 普通信息
ERROR, // 错误信息
FATAL, // core信息
DEBUG, // 调试信息
Logger.h文件
#pragma once
#include <string>
#include "noncopyable.h"
// 可变参打印日志信息 LOG_INFO("%s %d",arg1,arg2)
// #define LOG_INFO(logmsgFormat,...): 这行代码定义了一个名为 LOG_INFO 的宏。它接受两个参数:
// logmsgFormat: 这是一串定义日志消息格式的字符串。它可以包含占位符,例如 %s 代表字符串,%d 代表整数。
// ...: 这是一个可变参数列表,意味着它可以接受任意数量的额外参数。
// ##__VA_ARGS__: 这会展开可变参数列表并将它们传递给 snprintf 进行格式化。
#define LOG_INFO(logmsgFormat,...) \
do \
{ \
Logger &logger = Logger::instance(); \
logger.setLogLevel(INFO); \
char buf[1024]={0}; \
snprintf(buf,1024,logmsgFormat, ##_VA_ARGS__); \
logger.log(buf); \
} while(0)
#define LOG_ERROR(logmsgFormat,...) \
do \
{ \
Logger &logger = Logger::instance(); \
logger.setLogLevel(ERROR); \
char buf[1024]={0}; \
snprintf(buf,1024,logmsgFormat, ##_VA_ARGS__); \
logger.log(buf); \
} while(0)
#define LOG_FATAL(logmsgFormat,...) \
do \
{ \
Logger &logger = Logger::instance(); \
logger.setLogLevel(FATAL); \
char buf[1024]={0}; \
snprintf(buf,1024,logmsgFormat, ##_VA_ARGS__); \
logger.log(buf); \
} while(0)
// 把DEBUG部分隐藏不需要给用户使用
#ifdef MUDEBUG
#define LOG_DEBUG(logmsgFormat,...) \
do \
{ \
Logger &logger = Logger::instance(); \
logger.setLogLevel(DEBUG); \
char buf[1024]={0}; \
snprintf(buf,1024,logmsgFormat, ##_VA_ARGS__); \
logger.log(buf); \
} while(0)
#else
#define LOG_DEBUG(logmsgFormat,...)
#endif
enum LogLevel
{
INFO, // 普通信息
ERROR, // 错误信息
FATAL, // core信息
DEBUG, // 调试信息
};
// 日志类
class Logger : noncopyable
{
public:
// 获取日志唯一实例对象
static Logger &instance();
// 设置日志级别
void setLogLevel(int level);
// 写日志
void log(std::string msg);
private:
int logLevel_;
Logger() {}
};
Logger.cc文件
#include <iostream>
#include "Logger.h"
// 获取日志唯一实例对象
Logger &Logger::instance()
{
static Logger logger;
return logger;
}
// 设置日志级别
void Logger::setLogLevel(int level)
{
logLevel_=level;
}
// 写日志 [日志信息] 时间 msg
void Logger::log(std::string msg)
{
switch(logLevel_)
{
case INFO:
std::cout<<"[INFO]";
break;
case ERROR:
std::cout<<"[ERROR]";
break;
case FATAL:
std::cout<<"[FATAL]";
break;
case DEBUG:
std::cout<<"[DEBUG]";
break;
default:
break;
}
std::cout<<"time"<<":"<<msg<<std::endl;
}
这一行std::cout<<"time"<<":"<<msg<<std::endl;
我们将会编写一个时间类去补充进去
Timestamp类
我们有时候需要打印日期,我们写个简单时间工具类
Timestamp.h 和 Timestamp.cc文件
//Timestamp.h
#pragma once
#include <iostream>
#include <string>
class Timestamp
{
public:
Timestamp();
explicit Timestamp(int64_t);
static Timestamp now();
std::string toString() const;
private:
int64_t microSecondsSinceEpoch_; // 自纪元以来的微秒数
};
//Timestamp.cc
#include "Timestamp.h"
#include <time.h>
Timestamp::Timestamp() : microSecondsSinceEpoch_(0) {}
Timestamp::Timestamp(int64_t microSecondsSinceEpoch) :
microSecondsSinceEpoch_(microSecondsSinceEpoch)
{
}
Timestamp Timestamp::now()
{
// time(NULL)函数返回从1970年1月1日00:00:00 UTC到当前时间的秒数。
int64_t times = time(NULL);
return Timestamp(times);
}
std::string Timestamp::toString() const
{
char buf[128]={0};
// tm 结构体包含了时间戳的各个部分,例如年、月、日、时、分、秒等。
tm* tm_time =localtime(µSecondsSinceEpoch_);
snprintf(buf,128,"%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;
}
InetAddress 和copyable
我们建立一个服务器类需要封装socket IP和端口等,我们先创建InetAddress,muduo库的作者这个类是继承了copyable类的,我们也来实现
copyable.h
#pragma once
class copyable
{
protected:
copyable() = default;
~copyable() = default;
};
我们来封装一个ip地址的获取
InetAddress.h
#pragma once
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string>
#include "copyable.h"
class InetAddress:public copyable{
public:
InetAddress();
~InetAddress(){}
// 构造函数 端口和ip
explicit InetAddress(uint16_t ,std::string );
explicit InetAddress(const sockaddr_in& addr):addr_(addr){}
// 得到ip
std::string toIp()const;
// 得到ip端口
std::string toIpPort()const;
uint16_t toPort() const;
// 得到socket
const sockaddr_in* getSockAddr()const;
private:
sockaddr_in addr_;
};
InetAddress.cc
#include "InetAddress.h"
#include <strings.h>
#include <string.h>
InetAddress::InetAddress(uint16_t port,std::string ip="127.0.0.1")
{
bzero(&addr_,sizeof addr_);
addr_.sin_family=AF_INET;
addr_.sin_port = htons(port);
addr_.sin_addr.s_addr=inet_addr(ip.c_str());
}
std::string InetAddress::toIp()const
{
char buf[64]={0};
// addr_.sin_addr 中的 IPv4 地址转换为点分十进制表示法字符串并将其存储在 buf 中。
// AF_INET 表示 IPv4 地址。
::inet_ntop(AF_INET,&addr_.sin_addr,buf,sizeof buf);
return buf;
}
std::string InetAddress::toIpPort()const
{
//ip:port
char buf[64]={0};
::inet_ntop(AF_INET,&addr_.sin_addr,buf,sizeof buf);
size_t end = strlen(buf);
uint16_t port=ntohs(addr_.sin_port);
sprintf(buf+end,":%u",port); //把:端口的内容加在ip后面 %u将无符号十进制整数转换为字符串。
return buf;
}
uint16_t InetAddress::toPort() const
{
return ntohs(addr_.sin_port);
}
const sockaddr_in* InetAddress::getSockAddr()const
{
return &addr_;
}
浙公网安备 33010602011771号