POCO C++库学习和分析 -- 日志

【C++】POCO学习总结(十七):日志系统(级别、通道、格式化、记录流) POCO日志系统,很强大 阅读详情

日志对于程序来说是非常重要的,特别是对一些大型程序而言。一旦程序被发布,在现场日志几乎是程序员唯一可以获取程序信息的手段。Poco作为一个框架类库,提供了非常多的日志种类供程序员选用。文章将分两个部分,对于Poco日志进行介绍。第一部分主要以翻译Poco文档为主,第二部分则探讨Poco日志的实现。

1. Poco库日志接口

1.1  总体介绍 

         Poco中的日志模块主要涉及下列几个部分。
          1. 消息,日志和通道
          2. 格式
          3. 执行效率的考量

          模块框架图:

1.2  消息(Message类):

          1. 所有的消息都被存储并通过类Poco::Message传递
          2. 一个消息包括了下述特性:
             a. 优先级
             b. 消息源
             c. 消息内容
             d. 时间戳
             e. 进程与线程标记
             f. 可选参数(名字-值)对

           消息优先级:
           Poco定义了8种消息优先级:
                PRIO_FATAL
                PRIO_CRITICAL
                PRIO_ERROR
                PRIO_WARNING
                PRIO_NOTICE
                PRIO_INFORMATION
                PRIO_DEBUG
                PRIO_TRACE
          可以通过函数设置和获取消息优先级:

void setPriority(Priority prio)
                Priority getPriority() const


           消息源:
          消息源用来描述日志消息的源。通常状态下,使用Poco::Logger的名字来命名。因此应该合理的命名Poco::Logger的名字。
          可以通过函数设置和获取消息源:

 
  1. void setSource(const std::string& source)

  2. const std::string& getSource() const


   
           消息内容:
          在Poco中消息内容是不考虑格式和长度等问题的,只是消息内容。当消息最终输出时,消息内容有可能被类Poco::formatter修改。
          可以通过函数设置和获取消息内容:

 
  1. void setText(const std::string& text)

  2. const std::string& getText() const


           消息时间戳:
          记录消息产生时的时间戳,精度为毫秒。
          可以通过函数设置和获取时间戳:  

void setTime(const Timestamp& time)
                const Timestamp& getTime() const


           进程和线程标识符:
          进程标识符(PID)为长整形的int值,用来存储系统的进程ID。
          线程标识符(TID)同样为长整形的int值,用于存储当前线程的ID值。
          同样的当前线程的名字也会被存储。进程标识符(PID)、线程标识符(TID)、线程名在Poco::Message初始化时会自动生成。
          可以使用下列函数对进程标识符(PID)、线程标识符(TID)、线程名进行操作:

 
  1. void setThread(const std::string& threadName)

  2. const std::string& getThread() const

  3. void setTid(long tid)

  4. long getTid() const

  5. void setPid(long pid)

  6. long getPid() const


           消息参数:
          一个消息可以存储任意数目的name-value对 。
          name-value可以是任意字符串。
          消息参数可以被用于最终的格式输出。
          消息参数支持下标索引。

1.3 Logger类:

          应用程序可以使用Poco::Logger类去产生日志消息。每一个日志对象内部都包含了一个通道对象(Channel),通道用于最终把消息送到目的地。
          每一个logger对象都有名字,logger对象的名字会被用于命名所有由此对象产生的消息的消息源名称。名字一旦被设定,将不能被改变。
          每一个Poco::Logge对象都有其自己的优先级。有了优先级后,Poco::Logge对象便可以对消息进行过滤。只有消息的优先级比Poco::Logge对象的优先级高,消息才会被Poco::Logge对象所传递。

          Logger的继承体系。
          1. 基于Logger的名字,可以形成日志的树状继承体系。
          2. 一个Logger对象的名字包含了一个或多个部分,不同部分之间使用'.'分隔。每个日志组件的名称都包含了上级日志组件的名称
          3. 存在一个特殊的Logger,即root Logger,其名字为空。它是所有Logger的根。
          4. 对于Logger继承的深度Poco库并没有限制。

          下面是对于Logger继承的一个说明:
          Logger Hierarchy Example
             |
             |---- "" (the root logger)
                |
                |-----"HTTPServer"
                    |
                    |-----"HTTPServer.RequestHandler"
                    |
                    |-----"HTTPServer.RequestHandler.File"
                    |
                    |-----"HTTPServer.RequestHandler.CGI"
                    |
                    |------"HTTPServer.Listener"

           说明:
         1. 一个新的logger将继承它的上级日志组件的级别和通道。比如说,上例中"HTTPServer.RequestHandler.CGI"会继承"HTTPServer.RequestHandler"的日志级别和通道。
          2. 一旦一个logger被完全创建,它就将与它的上级无关。完全创建指,logger拥有自己的channel和日志级别,而不是和其它logger共用。换句话说,改变日志级别和通道将不会影响的到其他的已经存在的logger对象。
          3. 尽可能的对日志对象一次设置所有的参数,比如说日志级别和通道。

           记录消息:
          1. void log(const Message& msg)
          如果消息的优先级高于或者等于logger的优先级,消息将被传递到logger对应的通道中。消息传递时并不会发生改变。
          2. void log(const Exception& exc)
          使用最高优先级PRIO_ERROR,创建并记录消息。消息内容为异常内容。
          3. 使用下列不同优先级和给定的文字创建并记录消息

 
  1. void fatal(const std::string& text)

  2. void critical(const std::string& text)

  3. void error(const std::string& text)

  4. void warning(const std::string& text)

  5. void notice(const std::string& text)

  6. void information(const std::string& text)

  7. void debug(const std::string& text)

  8. void trace(const std::string& text)

          4. 使用给定的优先级和内容记录消息。消息的内容为16进制的给定Dump数据块。
             Logging Messages (cont'd)
          5. 判断日志等级
             bool is(int level) const              如果logger的日志级别等于或高于查询的日志级别,返回true

bool critical() const
       bool error() const
       bool warning() const
       bool notice() const
       bool information() const
       bool debug() const
       bool trace() const
       bool fatal() const

            如果logger的日志级别等于或高于给定的日志级别,返回true

           访问日志对象:
          POCO库在内部管理了一个全局的日志map。用户不需要自己创建logger对象,用户可以向POCO库申请一个logger对象的引用。POCO会根据需要创建新的日志对象。
          static Logger& get(const std::string& name)
          使用上面函数可以获取到给定名称所关联的logger对象的引用,如果有必要,POCO库会在内部创建一个logger对象。出于效率上的考虑,Poco使用文档推荐用户保存所使用的logger对象的引用,而不是频繁的调用此函数。理所当然的,POCO库能保证logger对象的引用始终有效。

          下面是一个例子:

#include "Poco/Logger.h"
using Poco::Logger;
int main(int argc, char** argv)
{
          Logger& logger = Logger::get("TestLogger");
          logger.information("This is an informational message");
          logger.warning("This is a warning message");
          return 0;
}

1.4 通道:

          通道的子类负责传递消息给最终目的地。比如说控制台或者日志文件等。
          每一个 Poco::Logger类对象(它本身也是Poco::Channel的子类)都对应着一个Poco::Channel类对象。在Poco库内部已经实现了各种Poco::Channel子类,用于向不同的目标输出日志,比如说控制台,日志文件,或者系统日志工具。用户可以定义自己的channel类。在内部Poco::Channel使用了 引用计数技术 来实现内存管理。

          通道属性:
          通道支持配置任意数目的属性,属性为一个名字值对。属性可以通过以下函数获取和设置:

 
  1. void setProperty(const std::string& name, const std::string& value)

  2. std::string getProperty(const sdt::string& name)

          这两个函数被定义在Poco::Configurable中,Poco::Configurable为Poco::Channel的父类。

1.4.1 控制台通道(ConsoleChannel)

          Poco::ConsoleChannel可以满足大多数的控制台输出。它只是简单的把消息内容写入了标准输出流(std::clog),并且不支持配置属性。它是根logger默认关联的通道(貌似这里有点误解,根logger并不会自动创建ConsoleChannel)。

1.4.2 windows控制台通道(WindowsConsoleChannel)

          Poco::WindowsConsoleChannel同ConsoleChannel类似,唯一不同的是向windows控制台输出。它只是简单把消息内容写入window控制台,并且不支持配置属性。向window控制台输出时,支持UTF-8编码。

1.4.3 空白通道(NullChannel)

          Poco::NullChannel通道会抛弃所有发向它的消息,并且忽略所有setProperty()函数设置的属性。

1.4.4 简单文件通道(SimpleFileChannel)

          Poco::SimpleFileChannel类实现了向日志文件输出的简单功能。对于每一个消息,其内容都会被添加到文件中,并使用一个新行输出。简单日志文件支持文件循环覆盖,一旦主日志文件超过确定的大小,第二个日志文件会被创建,如果第二个日志文件已经存在,会被截断。而当第二个日志文件超过大小限制,主日志文件将被覆盖。如此循环。

          简单文件通道属性
          path: 
主日志文件路径
           secondaryPath : 第二个日志文件路径。默认同主日志文件路径。
           rotation :日志循环覆盖模式。可以有以下几种选择:
               never: 不需要循环覆盖
               <n>: 如果超过 <n> 字节的话,循环覆盖
               <n> K: 如果超过 <n> K字节的话,循环覆盖
               <n> M: 如果超过 <n> M字节的话,循环覆盖

          下面是一个例子:

#include "Poco/Logger.h"
#include "Poco/SimpleFileChannel.h"
#include "Poco/AutoPtr.h"
using Poco::Logger;
using Poco::SimpleFileChannel;
using Poco::AutoPtr;
int main(int argc, char** argv)
{
          AutoPtr<SimpleFileChannel> pChannel(new SimpleFileChannel);
          pChannel->setProperty("path", "sample.log");
          pChannel->setProperty("rotation", "2 K");
          Logger::root().setChannel(pChannel);
          Logger& logger = Logger::get("TestLogger"); // inherits root channel
          for (int i = 0; i < 100; ++i)
          logger.information("Testing SimpleFileChannel");
          return 0;
}

1.4.5 文件通道

          Poco::FileChannel类提供了完整的日志支持。每一个消息的内容都会被添加到文件中,并使用一个新行输出。Poco::FileChannel类支持按文件大小和时间间隔对日志进行循环覆盖,支持自动归档(使用不同的文件命名策略),支持压缩(GZIP)和清除(根据已归档文件的日期或数量)归档日志文件。

           文件通道属性
          path: 
日志文件的路径
           rotation: 日志循环覆盖模式。可以有以下几种选择:
               never: 不需要循环覆盖
               <n>: 如果超过 <n> 字节的话,循环覆盖
               <n> K: 如果超过 <n> K字节的话,循环覆盖
               <n> M: 如果超过 <n> M字节的话,循环覆盖
               [day][hh:][mm]: 按照指定的日期和时间进行日志的循环覆盖
               daily/weekly/monthly: 按照日/周/月循环覆盖
               <n> hours/weeks/months: 按照<n>小时/周/月进行循环覆盖
           archive: 归档日志的目录名
               number:从0开始自动增加的数字,被添加到日志文件名后。最新的日志文件数字总是0。
               timestamp: 时间戳以YYYYMMDDHHMMSS格式被添加到日志文件名后
               times:指定循环的时间是按照本地时间还是按照UTC时间。本地时间和utc时间都是可以接受的合法时间。
               compress:自动压缩存档文件。指定true或者false。
              purgeAge:指定归档日志的最大期限。当日志的生成时间超过此期限,将被删除。格式为 <n> [seconds]/minutes/hours/days/weeks/months
               purgeCount:指定归档日志文件的最大数目。如果生成日志的数目超过此最大数目,生成日期最早的文件将被删除。

          下面是一个例子:

#include "Poco/Logger.h"
#include "Poco/FileChannel.h"
#include "Poco/AutoPtr.h"
using Poco::Logger;
using Poco::FileChannel;
using Poco::AutoPtr;
int main(int argc, char** argv)
{
          AutoPtr<FileChannel> pChannel(new FileChannel);
          pChannel->setProperty("path", "sample.log");
          pChannel->setProperty("rotation", "2 K");
          pChannel->setProperty("archive", "timestamp");
          Logger::root().setChannel(pChannel);
          Logger& logger = Logger::get("TestLogger"); // inherits root channel
          for (int i = 0; i < 100; ++i)
          logger.information("Testing FileChannel");
          return 0;
}

1.4.6 事件日志通道(EventLogChannel)

          Poco::EventLogChannel仅被使用于操作系统Windows NT中,它将把日志写到"Windows事件日志"中.Poco::EventLogChannel会把PocoFoundation.dll作为消息定义资源注册到"Windows事件日志"中。当使用Window事件查看器来查看系统事件日志时,事件查看器必须要找到PocoFoundation.dll,否则记录的日志消息将不能够被正常显示。

           事件日志通道属性
               name: 
事件源的名字,通常是程序名。
               loghost, host: 事件日志服务在运行的主机的名称。默认值为本地主机
                logfile: 日志文件的名称。默认是应用程序本身。

1.4.7 系统日志通道(SyslogChannel)

          Poco::SyslogChannel仅适用于Unix平台,会把日志输出到本地系统日志守护程序。
          包含RemoteSyslogChannel类的网络库,可以通过基于UDP的系统日志协议(Syslog protoco)把日志输出到远程的日志守护程序上。

1.4.8 异步通道:

          Poco::AsyncChannel允许在另外一个分离的线程中去记录通道的日志。这可以把产生日志的线程和记录日志的线程分开而实现解耦。所有的消息先被存储在一个先进先出的消息队列中,然后由一个单独的线程从消息队列中获取,并最终把消息发送到输出通道。

          下面是一个例子:

#include "Poco/Logger.h"
#include "Poco/AsyncChannel.h"
#include "Poco/ConsoleChannel.h"
#include "Poco/AutoPtr.h"
using Poco::Logger;
using Poco::AsyncChannel;
using Poco::ConsoleChannel;
using Poco::AutoPtr;
int main(int argc, char** argv)
{
          AutoPtr<ConsoleChannel> pCons(new ConsoleChannel);
          AutoPtr<AsyncChannel> pAsync(new AsyncChannel(pCons));
          Logger::root().setChannel(pAsync);
          Logger& logger = Logger::get("TestLogger");
          for (int i = 0; i < 10; ++i)
          logger.information("This is a test");
          return 0;
}

1.4.9 拆分通道(SplitterChannel)

          使用Poco::SplitterChannel可以把消息发送给一个或者多个其他的通道,即输出日志在多个目标中。使用下面的函数可以在SplitterChannel中加入一个新通道:
                void addChannel(Channel* pChannel)

          下面是一个例子

#include "Poco/Logger.h"
#include "Poco/SplitterChannel.h"
#include "Poco/ConsoleChannel.h"
#include "Poco/SimpleFileChannel.h"
#include "Poco/AutoPtr.h"
using Poco::Logger;
using Poco::SplitterChannel;
using Poco::ConsoleChannel;
using Poco::SimpleFileChannel;
using Poco::AutoPtr;
int main(int argc, char** argv)
{
          AutoPtr<ConsoleChannel> pCons(new ConsoleChannel);
          AutoPtr<SimpleFileChannel> pFile(new SimpleFileChannel("test.log"));
          AutoPtr<SplitterChannel> pSplitter(new SplitterChannel);
          pSplitter->addChannel(pCons);
          pSplitter->addChannel(pFile);
          Logger::root().setChannel(pSplitter);
          Logger::root().information("This is a test");
          return 0;
}

1.5 LogStream类

          Poco::LogStream类提供了一个日志的输出流接口。可以在日志流中,格式化输出日志记录消息。日志消息必须以std::endl(或CR和LF字符)结尾。

         下面是 LogStream在日志体系中的示意图:

          消息的优先级可以使用下列函数设定:

 
  1. LogStream& priority(Message::Priority prio)

  2. LogStream& fatal()

  3. LogStream& critical()

  4. LogStream& error()

  5. LogStream& warning()

  6. LogStream& notice()

  7. LogStream& information()

  8. LogStream& debug()

  9. LogStream& trace


          下面是一个例子:

#include "Poco/LogStream.h"
#include "Poco/Logger.h"
using Poco::Logger;
using Poco::LogStream;
int main(int argc, char** argv)
{
          Logger& logger = Logger::get("TestLogger");
          LogStream lstr(logger);
          lstr << "This is a test" << std::endl;
          return 0;
}

1.6  FormattingChannel类和Formatter类

          消息的格式

          


          FormattingChannel类和Formatter类负责格式化日志消息。Poco::FormattingChannel会把它接受到的每一个消息通过Poco::Formatter传递给下一个的输出通道。                        Poco::Formatter是所有格式类的基类,同通道一样,可以被设置属性。

1.6.1 PatternFormatter类

          Poco::PatternFormatter可以根据打印格式去格式化消息。想要知道更多细节,可以查看相关文档。

          下面是一个例子:

#include "Poco/ConsoleChannel.h"
#include "Poco/FormattingChannel.h"
#include "Poco/PatternFormatter.h"
#include "Poco/Logger.h"
#include "Poco/AutoPtr.h"
using Poco::ConsoleChannel;
using Poco::FormattingChannel;
using Poco::PatternFormatter;
using Poco::Logger;
using Poco::AutoPtr;
int main(int argc, char** argv)
{
          AutoPtr<ConsoleChannel> pCons(new ConsoleChannel);
          AutoPtr<PatternFormatter> pPF(new PatternFormatter);
          pPF->setProperty("pattern", "%Y-%m-%d %H:%M:%S %s: %t");
          AutoPtr<FormattingChannel> pFC(new FormattingChannel(pPF, pCons));
          Logger::root().setChannel(pFC);
          Logger::get("TestChannel").information("This is a test");
          return 0;
}

1. 7 日志效率的考虑:

          1. 创建消息可能要花费一定的时间(消息创建时需要获取系统当前时间、进程ID和线程ID)
          2. 创建一个有意义的消息也需要时间,因为按输出格式生成字符串是存在开销的
          3. 消息通常情况下是通过引用的方式传递给下一个通道。例外的情况是,FormattingChannel和AsyncChannel类。它们会生成消息的一个副本。
          4. 对于每一个日志(logger)对象来说,一条消息要么被输出,要么不被输出,这由日志和消息的级别共同决定。这个动作存在常数级别的开销,仅是两个int型的比较。
          5. 获取日志(logger)对象引用的操作开销是基于对数的,这由std::map的查找特性所决定。在查找过程中,日志(logger)对象名称的比较是线性的,这由std::string字符串比较特性所决定。
          6. 通常在一个程序中,获取一个日志(logger)对象引用(Logger::get())的操作,只会进行一次。
          7. 尽可能的避免频繁的调用Logger::get()函数,更好的方法是在通过函数获得日志(logger)对象引用后,保存它。
          8. 记录和输出日志的效率取决于日志输出的通道。通道的效率非常依赖于操作系统的实现。
          9. 构造消息(messages)的开销包括了构造字符串,字符拼接,数字格式化等。
          10. 在构造消息前,推荐先查询日志器的等级,以决定是否需要构造消息。查询等级可以使用函数is(), fatal(), critical()等。
          11. 在Poco库中提供了一些宏,用于在构造消息之前对日志等级进行检查。如poco_fatal(msg), poco_critical(msg), poco_error(msg)等。

          下面是一个例子:

 
  1. // ...

  2. if (logger.warning())

  3. {

  4. std::string msg("This is a warning");

  5. logger.warning(msg);

  6. }

  7.  
  8. // is equivalent to

  9. poco_warning(logger, "This is a warning");

  •  
【C++】POCO学习总结(十):Poco::Util::Application(应用程序框架) 在Linux平台上,继承Poco::Util::ServerApplication后,可以通过命令行参数“–daemon”来实现,作为守护进程运行。 阅读详情

相关推荐

POCO C++库学习和分析 -- 日志 (二)

POCO C++库学习和分析 -- 日志 (二) 2. Poco日志的实现 2.1 日志模块应该实现的业务          在讨论日志的实现之前,先来聊一下日志模块应该实现那些业务。日志的业务说简单可以很简单,就是输出记录。说复杂也复杂,来看它的复杂性:          首先,日志的输出对象是不同的,有控制台输出,本地文件输出,网络文件输出,输出到系统日志等。假如是网络日志,日

理性的幻想 7493

C++ POCO库(访问数据库,版本问题,本人配置失败)

官网下载源码:https://pocoproject.org/ 一、POCO库简介 学习一个框架前,要先明白它的是什么,为什么,怎么用.下面这些文字,是从中文poco官网上转过来的,正如poco c++库的特点,非常清晰,代码风格更是一目了然. poco开发库的特点,非常适合写后台处理程序,效率也是很高的.前台界面程序使用Qt框架库,非常好,两个库相辅相成,可解决项目上的大部分问题. ...

csdndenglu的专栏 2390

【C++】开源:Poco可移植组件库配置与使用

Poco库是强大的的跨平台C++库,可以用来编写多平台的网络应用程序。

DevFrank的博客 3642

POCO C++库学习和分析 -- 日志 (一)

POCO C++库学习和分析 -- 日志 (一)          日志对于程序来说是非常重要的,特别是对一些大型程序而言。一旦程序被发布,在现场日志几乎是程序员唯一可以获取程序信息的手段。Poco作为一个框架类库,提供了非常多的日志种类供程序员选用。文章将分两个部分,对于Poco日志进行介绍。第一部分主要以翻译Poco文档为主,第二部分则探讨Poco日志的实现。 1. P

理性的幻想 1万+

全面解析Poco C++库:跨平台网络编程的利器

本文还有配套的精品资源,点击获取 简介:Poco C++ Libraries,简称POCO,是一个开源且功能强大的C++类库集合,特别适用于开发跨平台网络相关应用。POCO库以其轻量级、模块化的设计,丰富的网络通信协议支持,以及数据解析、数据库访问、加密安全、日志记录、线程管理等功能组件,为开发者提供高效可靠的软件开发解决方案。文档“poco-1.7.6-all-doc”详...

weixin_42502040的博客 6683

从零到一:用AXI DataMover在Zynq MPSoC上实现高效DMA传输(附Vitis HLS驱动示例)

本文详细介绍了如何在Xilinx Zynq UltraScale+ MPSoC平台上使用AXI DataMover实现高效的DMA数据传输。通过解析AXI DataMover架构、Vivado工程配置、Vitis HLS驱动开发及性能优化技巧,帮助开发者快速构建高性能数据传输通道,并提供了可直接复用的代码示例。

weixin_42520796的博客 424

poco mysql longtext_POCO C++库学习和分析 -- 日志 (一)

POCO C++库学习和分析 -- 日志(一)日志对于程序来说是非常重要的,特别是对一些大型程序而言。一旦程序被发布,在现场日志几乎是程序员唯一可以获取程序信息的手段。Poco作为一个框架类库,提供了非常多的日志种类供程序员选用。文章将分两个部分,对于Poco日志进行介绍。第一部分主要以翻译Poco文档为主,第二部分则探讨Poco日志的实现。1. Poco库日志接口1.1 总体介绍Poco中的...

weixin_34698515的博客 505

黑客渗透测试后门隐藏技术揭秘

本文介绍了在授权渗透测试中隐藏后门文件(muma.exe)的多种技术手段。主要包括:通过WinRAR自解压脚本将后门与正常程序捆绑实现双开;利用系统自动运行目录和注册表实现开机自启;修改文件图标伪装成常用软件;将文件存放在冷门系统目录;设置系统+隐藏双重属性增强隐蔽性。此外还涉及对抗安全软件的加壳(UPX)、免杀(msfvenom编码)技术,以及进程注入、日志清除等运行隐藏方法。所有技术仅限合法授权测试使用,未经授权使用将面临法律责任。

m0_60781580的博客 1040

POCO C++库学习和分析 -- 序

POCO C++库学习和分析 -- 序 1. POCO库概述: POCO是一个C++的开源库集。同一般的C++库相比,POCO的特点是提供了整一个应用框架。如果要做C++程序应用框架的快速开发,我觉得STL+boost+Poco+Qt+Mysql实在是个不错的组合。 下面的这张图提供了POCO库的一个结构。 对于POCO概述更加详细的介绍,可以看

u010129251的专栏 2万+

带挂牵引车前向运动模型推导及仿真实现

牵引车-半挂车的车辆结构与普通的车辆相比增加了一个半挂车,它们之间通过鞍座相连接,为了分析半挂牵引车运动过程中的位姿和状态,本文将基于车辆的机械结构建立对应的运动学模型,该模型基于以下假设: 车辆行驶过程中,道路平坦且无凸凹; 车辆低速行驶,且运行过程中车身无侧倾和俯仰运动; 车辆行驶过程中,轮胎无形变,无侧向滑动,且无侧向力; 牵引车和半挂车均满足阿克曼转向几何原理; 牵引车与半挂车不会发现折叠。

jianmo的博客 3182

基于STM32的超声波流量计设计

本项目基于STM32微控制器设计了一种超声波流量计,采用时间差法测量液体或气体的流速,计算流量并通过显示屏实时显示,同时支持远程数据传输。本设计通过STM32微控制器实现了基于时间差法的超声波流量计,集成了超声波信号采集、流量计算、状态显示和远程通信功能。本系统需要实现超声波信号的实时采集与处理,计算流速和流量,并将数据通过OLED显示和无线模块上传。系统需具备高精度的时间测量能力和良好的抗干扰能力。通过计算超声波在顺流和逆流方向上的传播时间差,结合管道直径与流体特性,计算流速并进一步计算流量。

stm32d1219的博客 2348

POCO C++库学习和分析

POCO C++库学习和分析 -- 序 1. POCO库概述: POCO是一个C++的开源库集。同一般的C++库相比,POCO的特点是提供了整一个应用框架。如果要做C++程序应用框架的快速开发,我觉得STL+boost+Poco+Qt+Mysql实在是个不错的组合。 下面的这张图提供了POCO库的一个结构。   对于POCO概述更加详细的介绍,可以看一下官方网站和《POCO C++库...

浩瀚之水的专栏 1487

【开源】STM32+ESP8266+MQTT多传感器数据上云OneNET(易拓展,带操作系统FreeRTOS)

【开源】STM32+ESP8266+MQTT多传感器数据上云OneNET(易拓展) 文章目录【开源】STM32+ESP8266+MQTT多传感器数据上云OneNET(易拓展)1. 相关连接1.1 本项目相关连接1.2 无操作系统简易版(旧版,有OneNET云平台设备创建和应用配置,本文不再赘述):2. 具体功能3. 硬件环境4. 云平台环境配置5. 接线6. 功能展示6.1 数据流6.2 APP应用管理6.3 串口数据7. 源码详解7.1 源码文件解析7.2 服务器与wifi配置相关7.3 源码框架7.4

ssssadw的博客 2万+

POCO C++库学习和分析 -- 异常、错误处理、调试

POCO C++库学习和分析 -- 异常、错误处理、调试 1. 异常处理         C++同C语言相比,提供了异常机制。通过使用try,catch关键字可以捕获异常,这种机制使得程序员在程序异常发生时,可以通过判断异常类型,来决定程序是否继续执行,并在程序结束之前优雅的释放各类资源。当然对于C++的异常机制也存在着很多的争议。在这里,并不对此展开讨论,只介绍一下Poco中的异

理性的幻想 7213

UG NX二次开发基础篇-外部模式与DLL内部模式(二 DLL内部模式)

通常情况下,我们希望我们的外挂,在UG启动的时候,就自动加载我们的外挂,并以菜单和工具条的方式,显示在UG上面。当然,这也是市面上所有外挂的操作,因为您不可能要求你的用户,以手工加载的方式,去调用你的外挂吧。在上一篇中,有粉丝留言说,启动 bat 文件,启动EXE外挂,会提示无法找到DLL的错误,这是因为UG的环境变量设置有问题,这里,我们把BAT文件作一个修改,直接改为实际目录。EXE外部模式,还有很多部分需要添加的,如参数的传递、输出消息的显示、UG操作的消息显示,等等。Dll执行结束后,会调用。

u014657217的博客 1653

计算机组成原理(第三版)唐朔飞-第六章计算机的运算方法-课后习题(17-32)

计算机组成原理(第三版)唐朔飞-第六章计算机的运算方法-课后习题(17-32)

weixin_45735391的博客 12万+

POCO C++库学习和分析 -- Foundation库的结构

POCO C++库学习和分析 --  Foundation库结构 Foundation库是POCO库集中的一个,提供了编程时的一些常用抽象。在程序中被分成了18个部分,分别是: 1)Core 这部分除了建立跨平台库的基础头文件外,最有意义的部分是分装了原子计数的基本类(AtomicCounter),以及垃圾收集的一些类,如AutoPtr,SharedPtr。 2)Cache 顾名

理性的幻想 7887

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

【C++】POCO学习总结(五):功能介绍

POCO第一个版本于 2005 年 2 月发布POCO完全免费:POCO C++ 库根据 Boost 软件许可证获得许可。非常自由的许可证,鼓励商业和非商业使用。

郭老二 2765

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

上一篇: android ndk开发 输出崩溃信息
下一篇: python psutil 官方文档
周亚权
博客等级 码龄14年 83粉丝 64原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值