AndreaDO

导航

构建自己的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.hTimestamp.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(&microSecondsSinceEpoch_);
  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_;
}

posted on 2024-03-17 20:02  AndreaDO  阅读(72)  评论(0)    收藏  举报