首页 > 其他分享 >详解 Muduo 网络服务和日志模块

详解 Muduo 网络服务和日志模块

时间:2024-06-06 19:58:47浏览次数:13  
标签:muduo 网络服务 示例 LOG EventLoop Muduo 日志 函数

这篇文章主要目的是介绍muduo 的网络服务模块和日志模块。

muduo网络服务

在muduo网络库中,最重要的初始化服务,需要涉及两个核心模块,muduo::net::EventLoop和muduo::net::TcpServer。muduo::net::EventLoop不需要我们去设置,我们需要做的只是给Server指定一个EventLoop对象,并在开启Server后开启EventLoop。muduo::net::TcpServer负责muduo网络服务的基础配置,如listenAddr的设置、EventLoop的设置、setConnectionCallback连接回调函数的绑定和setMessageCallback消息回调函数的绑定等。其中绑定的连接回调函数和消息回调函数由我们自定义,定义内容取决于我们的具体需求。

具体的示例如下:

#include "muduo/net/TcpServer.h"
#include "muduo/net/EventLoop.h"

#include <functional>  // 引入functional头文件,用于std::bind函数

using namespace muduo;  // 使用muduo命名空间
using namespace muduo::net;  // 使用muduo::net命名空间

// 定义EchoServer类
class EchoServer 
{
public:
    // 构造函数,接收一个EventLoop指针和一个InetAddress对象
    EchoServer(EventLoop* loop, const InetAddress& listenAddr)
    : loop_(loop),  // 初始化EventLoop指针
      server_(loop, listenAddr, "EchoServer")  // 初始化TcpServer对象
    {
        // 设置连接回调函数,当新的连接建立时,会调用onConnection方法
        server_.setConnectionCallback(std::bind(&EchoServer::onConnection, this, _1));
        // 设置消息回调函数,当接收到新的消息时,会调用onMessage方法
        server_.setMessageCallback(std::bind(&EchoServer::onMessage, this, _1, _2, _3));
    }

    // 启动服务器
    void start()
    {
        server_.start();
    }

private:
    // 连接回调函数,接收一个TcpConnectionPtr智能指针
    void onConnection(const TcpConnectionPtr& conn);

    // 消息回调函数,接收一个TcpConnectionPtr智能指针,一个Buffer指针和一个Timestamp对象
    void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time);

    EventLoop* loop_;  // EventLoop指针
    TcpServer server_;  // TcpServer对象
};

上述例子创建了一个简单的 EchoServer 类,对 muduo 提供的网络服务进行简单的封装。成员变量有 EventLoop* 类型的 loop_ 和 TcpServer 类型的 server_,EventLoop* 对象定义在 TcpServer 之前,因为初始化列表按定义顺序进行初始化,而 TcpServer 依赖于 EventLoop*。可以看到 EventLoop* 对象的创建只需要简单的声明,但是 TcpServer 则需要设置 EventLoop* 、const InetAddress& 、和 const string& nameArg,即事件循环、IP地址和服务名称。除此之外,TcpServer 对象还可以设置回调函数,这是我们需要自定义的部分。

setConnectionCallback 设置连接回调函数,连接回调函数就是当有一个新的连接到达时或者连接断开时会被调用的函数。我们可以在连接回调函数中设置日志或者更新连接状态等。

setMessageCallback 设置消息回调函数,消息回调函数就是当一个新的消息到达时会被调用的函数,我们可以在消息回调函数中处理到达的消息,根据具体的消息内容进行对应处理。

上述示例中的 setConnectionCallback 和 setMessageCallback 绑定的回调函数是 EchoServer 的类成员函数 onConnection 和 onMessage。下面是其简单的实现示例:

void EchoServer::onConnection(const TcpConnectionPtr& conn)
{
    std::cout << conn->peerAddress().toIpPort() << " -> "
                << conn->localAddress().toIpPort() << " is "
                << (conn->connected() ? "UP" : "DOWN") << std::endl;
}

void EchoServer::onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time)
{
    string msg(buf->retrieveAllAsString());
    std::cout << conn->name() << " recv " << msg.size() << " bytes at " << time.toString() << std::endl;
    conn->send(msg);
}

在上述示例中,onConnection 向终端输出对端地址和当前地址连接的状态,onMessage 接收对端发送的消息并转发回去以及向终端输出发送消息的连接名称、消息大小和时间戳。

日志

muduo 提供日志模块记录程序运行的过程信息,并且 muduo 还提供了异步日志模块 AsyncLogging 来防止日志的输出阻塞程序的运行。

在介绍 muduo 日志模块的具体使用示例之前,我们需要了解一下日志等级。

在 muduo 中存在 6 中日志级别:

  enum LogLevel
  {
    TRACE,
    DEBUG,
    INFO,
    WARN,
    ERROR,
    FATAL,
    NUM_LOG_LEVELS,// 日志等级数量
  };

分别是 TRACE, DEBUG, INFO, WARN, ERROR, FATAL。分别用于记录追踪信息、调试信息、一般信息、警告信息、错误信息、致命错误信息,然后日志等级是逐渐递增的,TRACE 最低、FATAL 最高。并且 muduo 提供了对应的宏来方便记录各个级别的日志信息,分别是LOG_TRACE、LOG_DEBUG、LOG_INFO、LOG_WARN、LOG_ERROR、LOG_FATA,除此之外,muduo 还提供 LOG_SYSERR、LOG_SYSFATAL 用于记录系统错误。这八个日志宏中,前三种只有在当前日志等级等于小于对应等级时才会记录日志。如:当日志级别为 INFO 时,使用 LOG_TRACE 和 LOG_DEBUF 来指定的日志信息不会被记录,只有使用 LOG_INFO 及以上等级对应的宏指定的日志才会被记录。后五种日志宏则会忽视当前的日志等级,即无论当前日志等级是什么,都会进行记录。如:当当前日志等级为 FATAL 时,使用 LOG_ERROR 记录的日志照样会被记录。其中,特别的是 LOG_SYSFATAL,它在记录完日志后会立即退出程序(Abort)。

我们可以使用muduo::Logger::setLogLevel(muduo::Logger::LogLevel);来指定日志等级。

下面介绍如何使用日志模块:

我们使用muduo::Logger设置日志系统的基本配置,如输出函数(即使用LOG宏记录日志时,会调用的函数)、日志级别等。当我们需要一个异步日志模块时,我们会使用 AsyncLogging 对象,我们可以指定 AsyncLogging 对象能承载的大小,也就是单个日志文件能承载的大小,当超过这个大小就会创建新的日志文件。

具体的示例代码如下:

下面示例在 网络服务 示例的基础上进行扩展。

//...
void EchoServer::onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) {
    //...
}
// ...

// 设置日志文件的大小为500MB。当日志文件大小达到这个值时,会自动创建一个新的日志文件。
int kRollSize = 500*1000*1000;

// 定义一个全局的unique_ptr,指向一个AsyncLogging对象。AsyncLogging是muduo库中的一个类,用于异步写日志。
std::unique_ptr<muduo::AsyncLogging> g_asyncLog;

// 定义一个函数,用于异步输出日志。这个函数会被设置为Logger类的输出函数。
void asyncOutput(const char* msg, int len) 
{
    // 将日志信息添加到AsyncLogging对象中。AsyncLogging对象会在另一个线程中将这些日志信息写入文件。
    g_asyncLog->append(msg, len); 
}

// 定义一个函数,用于设置日志系统。
void setLogging(const char* argv0) 
{
    // 设置Logger类的输出函数为asyncOutput。这样,当我们使用LOG宏记录日志信息时,这些信息会被传递给asyncOutput函数。
    muduo::Logger::setOutput(asyncOutput); 

    // 设置日志级别为INFO。这样,只有级别大于或等于INFO的日志信息才会被记录。
    muduo::Logger::setLogLevel(muduo::Logger::INFO); 

    char name[256];
    // 将程序的名称复制到name数组中。
    strncpy(name, argv0, 256); 

    // 创建一个新的AsyncLogging对象,并将其赋值给g_asyncLog。这个对象的名称为程序的名称,日志文件的大小为kRollSize。
    g_asyncLog.reset(new muduo::AsyncLogging(::basename(name), kRollSize)); 

    // 启动AsyncLogging对象。这会创建一个新的线程,用于异步写日志。
    g_asyncLog->start(); 
}

上述示例设置了一个异步日志系统,当有日志需要输出时,不直接写日志,而是添加到 muduo::AsyncLogging 对象中,然后由一个单独的线程异步写日志,当日志文件大小达到 50010001000 bytes时,创建新的文件。

以上就是这篇文章的全部内容。

上面示例代码来自于muduo-tutorial,可以前往muduo-tutorial的GitHub仓库查看完整示例代码。

标签:muduo,网络服务,示例,LOG,EventLoop,Muduo,日志,函数
From: https://blog.csdn.net/a2025834646/article/details/139413357

相关文章

  • journal日志管理
    1、systemd-journald详解systemd-journald日志默认保存在/run/log/journal中,重启会被清楚,如果存在/var/log/journal目录,systemd-journald日志会自动改为记入在这个目录中,同时日志轮转也会启动,日志轮状每月启动,默认情况下,日志大小不能超过文件系统的10%,也不能造成文件系统的可......
  • 日志
    系统都需要做日志功能,包括系统异常报错、非法访问等等都想要进行记录和统计,这样的数据数量会很多却又跟具体的业务没有太大关系,所以一般情况下可能会选择以txtpublicstaticvoidWriteLog(stringlogstring){try{stringpath=AppDomain.CurrentDoma......
  • 003基于SSM+Jsp+Mysql的美好生活日志网
    开发语言:Java框架:ssm技术:JSPJDK版本:JDK1.8服务器:tomcat7数据库:mysql5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:Maven3.3.9系统展示前台首页用户注册用户登录日记信息管理员登录用户管理日记信息管理美食信息管理景点信息管......
  • yolov5训练日志
      (wind_2021)J:\PytorchProject\yolov5_train_car_2024060501>(wind_2021)J:\PytorchProject\yolov5_train_car_2024060501>pythontrain_20230320.py--img-size640--batch-size2--epochs300--data./data/myvoc.yaml--cfg./models/yolov5m.yaml--......
  • Java中的错误处理和日志记录:提升应用的健壮性和可维护性
            在Java开发中,有效的错误处理和日志记录是确保应用健壮性和可维护性的关键。通过恰当的异常处理和详尽的日志信息,开发者可以迅速定位和解决问题,同时提供程序运行的透明度。本文将探讨Java中的错误处理最佳实践和日志记录技术,包括常用的日志框架和配置方法。###......
  • kubernetes 集群开启审计日志
    原文链接:https://maoqide.live/posts/cloud/kubernetes-auditKubernetes审计关于Kubernetes审计的详细信息,可以查看官方文档:https://kubernetes.io/zh-cn/docs/tasks/debug-application-cluster/audit/简单来说,kube-apiserver能够记录所有请求到集群的请求和响应。根据你配......
  • 跟着杨中科学习(二)日志
    日志系统日志级别Trace<Debug<Information<Warning<Error<Critical输出到控制台NugetMicrosoft.Extensions.LoggingMicrosoft.Extensions.Logging.ConsoleDI注入services.AddLogging(logBuilder=>{ logBuilder.AddConsole();//可多个ProciderlogBuilder.SetMini......
  • 日志工具类之“根据标记的注解进行指定的字段日志记录-在展示方式上会美观一些”
    一、使用方法在添加、编辑等操作功能时可以使用该方案,在需要记录日志的实体类字段中进行注解标注。并标明对应的字段名二、代码1.使用LoggerUtils工具类生成日志publicJsonResultsavePrice(Priceprice){if(price.getId()!=null){String......
  • java框架-日志-体系与级别-技巧
     体系一是提供了统一的日志门面API,即图中紫色部分,实现了中立的日志记录API。二是桥接功能,即图中蓝色部分,用来把各种日志框架的API(图中绿色部分)桥接到SLF4JAPI。这样一来,即便你的程序中使用了各种日志API记录日志,最终都可以桥接到SLF4J门面API。三是适配功能,即图......
  • golang 使用 zap logger 加入Lumberjack 写日志
    golang使用zaplogger加入Lumberjack写日志Cd进入项目目录gogetgo.uber.org/zap/zapcoregoget-ugithub.com/natefinch/lumberjack关于下面代码说明: funcgetLogWriter()zapcore.WriteSyncer{lumberJackLogger:=&lumberjack.Logger{Filename:......