POCO C++庫導遊

英文原文: http://pocoproject.org/docs/00100-GuidedTour.html#2

 

簡介
POCO C++庫是開源的用於簡化和加速C++開發面向網絡、可移植應用程序的C++庫集,POCO庫和C++標準庫可以很好的集成並填補了C++標準庫缺乏的功能空隙。POCO庫的模塊化、高效的設計及實現使得POCO特別適合嵌入式開發。在嵌入式開發領域,由於C++既適合底層(設備I/O、中斷處理等)和高層面向對象開發,越來越流行。當然POCO也準備好了面對企業級挑戰。

包含4個核心庫及一些附加庫. 這4個核心庫是: Foundation, XML, Util 和 Net. 附加庫中其中2個是NetSSL和Data,NetSSL爲Net庫中的網絡類提供SSL支持, Data庫提供訪問不同SQL數據庫的一致性接口。 POCO以網絡中心的跨平臺C++軟件開發,就像蘋果的Cocoa之餘Mac開發, 或Ruby on Rails 之餘Web開發—強大而不失簡單有趣的用於創建應用的平臺. POCO 嚴格使用標準ANSI/ISO C++創建, 包含標準庫. 程序庫的貢獻者試圖在使用C++高級特性、易於理解的類、乾淨的代碼、連續及易於維護間得到平衡.

Foundation基本庫
Foundation庫是POCO的心臟.它包含底層平臺的封裝層,也包含經常使用的工具類和函數. 包含規定字節大小整數類型, 轉換整數與字節順序的函數, Poco::Any 類 (基於 boost::any), 錯誤處理及調試工具, 包含各種異常類和支持斷言. 同時也包含一些內存管理類, 包括基於引用計數的智能指針,和用與buffer管理及內存池的類. 對於字符串的處理, POCO包含一些函數和其他的東西, 串trim操作, 大小寫敏感的比較和大小寫轉換. 以類對Unicode的基本支持:轉換文本的不同編碼, 包括UTF-8 和 UTF-16. 支持格式化和解析數字, 包括sprintf 的類型安全變量. 還提供了基於著名的PCRE 庫(http://www.pcre.org)的正則表達式。

POCO提供多種變量的日期和時間的處理類。在訪問文件系統方面, POCO 擁有Poco::File 、 Poco::Path 類, 和 Poco::DirectoryIterator 類.在許多應用程序中,其中一部分需要通知其他部分自己這邊發生的事情. POCO中的Poco::NotificationCenter、 Poco::NotificationQueue 和 events (類似 C
# events) 使這種工作變得容易. 下面的示例顯示如何使用POCO的 events. 示例中, 類Source 的公共event命名爲theEvent,該event有一個int型參數. 用戶可調用操作符 +=訂閱改事件和調用-=操作符取消訂閱, 同時傳遞對象指針和成員函數指針.事件可通過調用()操作符發射, 見 Source::fireEvent().

#include "Poco/BasicEvent.h"
#include "Poco/Delegate.h"
#include <iostream>
using Poco::BasicEvent;
using Poco::Delegate;
class Source{
public:   
    BasicEvent<int> theEvent;
    void fireEvent(int n){
      theEvent(this, n);   

    }
};

class Target{
public:
    void onEvent(const void* pSender, int& arg){
      std::cout << "onEvent: " << arg << std::endl;
    }
};

int main(int argc, char** argv){
Source source;
Target target;
source.theEvent += Delegate<Target, int>(&target,&Target::onEvent);
source.fireEvent(42);
source.theEvent -= Delegate<Target, int>(&target,Target::onEvent);
return 0;
}

POCO 中的stream類已經提到過. stream作爲Poco::BinaryReader 和 Poco::BinaryWriter 的參數用於寫二進制數據到流中, 自動、透明地處理字節順序問題.

在複雜的多線程應用中,查找問題和bug的僅有方式就是編寫廣泛的日誌信息. POCO 提供強大可擴展的日誌框架,該框架支持過濾、路由到不同的通道以及格式化日誌信息. 日誌消息可以寫入console、文件、Windows 事件日誌、Unix的syslog後臺或網絡中.如果POCO提供的通道不夠使用,可以很方便的使用新類擴展日誌框架.

對於在運行時裝載(及卸載) 共享庫, POCO提供底層的Poco::SharedLibrary 類. 基於它的Poco::
classLoader 類模板和支持框架, 允許在運行時動態裝載和卸載C++類, 類似於JAVA和.NET. 類裝載框架使得以平臺無關的方式編寫應用程序插件成爲小菜一碟。

最後, POCO Foundation 包含在不同級別上的多線程封裝. 從Poco::Thread 類和一般同步原子(Poco::Mutex, Poco::ScopedLock, Poco::Event, Poco::Semaphore, Poco::RWLock), Poco::ThreadPool 類及支持thread-local 存儲, 到高級別的活動對象(active object)的封裝. 簡單點兒說, 活動對象(active object)是擁有運行於自有線程中的方法的類. 這使得異步成員函數調用成爲可能— 調用成員函數, 在函數執行期間, 做一堆其他的事情, 然後獲得函數的返回值. 下面的示例展示在POCO中是如何做的. ActiveAdder 類定義一個活動方法add(), 由addImpl()成員函數實現. 在main()中調用活動方法產生Poco::ActiveResult (also known as a future), 最後獲得函數的返回值。


#include "Poco/ActiveMethod.h"
#include "Poco/ActiveResult.h"
#include <utility>
using Poco::ActiveMethod;
using Poco::ActiveResult;
class ActiveAdder{
public:
    ActiveObject(): activeAdd(this, &ActiveAdder::add){
    }
   
    ActiveMethod<int, std::pair<int, int>, ActiveAdder> add;
private:
    int addImpl(const std::pair<int, int>& args){
     return args.first + args.second;
    }
};

int main(int argc, char** argv){
    ActiveAdder adder;
    ActiveResult<int> sum = adder.add(std::make_pair(1, 2)); // do other things
    sum.wait();    std::cout << sum.data() << std::endl;     return 0;}The XML Library
POCO XML 庫支持讀取, 處理及寫XML. 遵循POCO的一個指導原則— 不要試圖重新發明已經存在的工作— POCO's XML 庫支持工業標準SAX (版本2) 及DOM接口, 很多有XML經驗的開發人員對此比較熟悉. SAX,XML的簡單API (http://www.saxproject.org),定義了基於事件的XML讀接口. 基於SAX的XML 解析器在讀取XML文檔時但它讀到一個元素時會通知應用程序, 字符數據, 或其他人爲定義的XML元素. SAX解析器不需要將整個XML文檔裝載到內存中, 因此它可用於高效測解析巨大的XML文件. 相反, DOM (文檔對象模型, http://www.w3.org/DOM/) 讓應用程序訪問整個XML文檔, 使用樹形的對象層級. 要達到此目的,POCO提供的 DOM 解析器需要將整個文檔裝載到內存. 爲減小DOM文檔的內存佔用量, POCO DOM 實現使用使用字符串spooling,經常使用的字符串如元素和屬性名僅存儲一次. XML 庫基於Expat 開源XML 解析器庫 (http://www.libexpat.org). 基於Expat 的是SAX 接口, 基於SAX接口的是DOM的實現. 對字符串, XML 庫使用std::string, UTF-8編碼. 這是的XML庫與應用程序其他部分的接口變得簡單. 在未來的版本中將提供對XPath 和 XSLT的支持。

Util 庫
Util 庫的名稱可能會給人一些誤導, 因爲它包含了創建命令行和服務器應用的框架. 包括命令行參數處理支持(校驗, 綁定到配置屬性, etc.) 及管理配置信息. 支持不同的配置文件格式— Windows形式的 INI 文件, Java-類型的屬性文件, XML文件及Windows註冊表.

對服務器應用程序,框架提供對Windows服務和Unix後臺的透明支持. 每個服務器應用可以註冊以Windows服務運行, 不需要額外的代碼.當然, 所有的服務器應用程序仍然可以按命令行方式運行, 這使得測試和調測容易.

Net 庫
POCO's Net 庫使得編寫基於網絡的應用容易. 不管是應用是簡單的通過純TCP socket發送數據還是需要完整的內建HTTP server的應用,都可以在Net庫中找到有用的東西。

在最底層, Net庫包含socket類, 支持TCP流和server sockets, UDP sockets, multicast sockets, ICMP 及 raw sockets. 如果需要安全sockets, NetSSL 庫提供支持, 實現使用了 OpenSSL (http://www.openssl.org). 基於socket 類提供兩個框架創建TCP服務器 — 一個是多線程服務器(每個連接一個線程, 從線程池獲得), 一個是基於Acceptor-Reactor模式的服務器. 多線程 Poco::Net::TCPServer 類及其支持框架也是POCO's HTTP server 實現的基礎. 在客戶端, Net庫提供類與HTTP servers通信, 要使用ftp協議發送和接收文件, 使用SMTP發送郵件消息 (包括附件) 和從POP3 server接收郵件

全部放在一起
下面的例子示例使用POCO庫如何實現一個簡單的HTTP服務器. 服務器返回顯示當前日期和時間的HTML文檔. 用於創建作爲Windows服務或Unix後臺進程的服務器應用程序的應用框架。當然, 同一的可執行程序也可直接在shell啓動. 要使用HTTP server框架, TimeRequestHandler 類定義爲服務器返回包含當前日期和時間的HTML文檔作爲請求的響應. 對每個請求, 使用日誌框架對其記錄. 與 TimeRequestHandler 類一起, 相關的工廠類, TimeRequestHandlerFactory; 工廠的實例傳送給HTTP server 對象. HTTPTimeServer 應用類定義了命令行參數幫助,通過重載Poco::Util::ServerApplication的成員函數defineOptions()。在HTTP server啓動前,它也讀取缺省的應用程序配置文件(在initialize()) 和在main()中獲取配置屬性的值。


#include "Poco/Net/HTTPServer.h"
#include "Poco/Net/HTTPRequestHandler.h"
#include "Poco/Net/HTTPRequestHandlerFactory.h"
#include "Poco/Net/HTTPServerParams.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/HTTPServerParams.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Timestamp.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/Exception.h"
#include "Poco/ThreadPool.h"
#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include <iostream>
using Poco::Net::ServerSocket;
using Poco::Net::HTTPRequestHandler;
using Poco::Net::HTTPRequestHandlerFactory;
using Poco::Net::HTTPServer;
using Poco::Net::HTTPServerRequest;
using Poco::Net::HTTPServerResponse;
using Poco::Net::HTTPServerParams;
using Poco::Timestamp;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
using Poco::ThreadPool;
using Poco::Util::ServerApplication;
using Poco::Util::Application;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::OptionCallback
using Poco::Util::HelpFormatter;
class TimeRequestHandler: public HTTPRequestHandler{
public:TimeRequestHandler(const std::string& format): _format(format){}
void handleRequest(HTTPServerRequest& request,
HTTPServerResponse& response){
    Application& app = Application::instance();
    app.logger().information("Request from "+
      request.clientAddress().toString());
    Timestamp now;
std::string dt(DateTimeFormatter::format(now, _format));
    response.setChunkedTransferEncoding(true);
    response.setContentType("text/html");
    std::ostream& ostr = response.send();
    ostr << "<html><head><title>HTTPTimeServer powered by"
      "POCO C++ Libraries</title>";
      ostr << "<meta http-equiv=/"refresh/" content=/"1/"></head>";
      ostr << "<body><p style=/"text-align: center; "
       "font-size: 48px;/">";
      ostr << dt;
      ostr << "</p></body></html>";
    }
private:
    std::string _format;
};

class TimeRequestHandlerFactory: public HTTPRequestHandlerFactory{
public:
TimeRequestHandlerFactory(const std::string& format):
_format(format){
    }
   
HTTPRequestHandler* createRequestHandler(
    const HTTPServerRequest& request){
    if (request.getURI() == "/")
      return new TimeRequestHandler(_format);
    else
      return 0;
    }
private:
std::string _format;
};

class HTTPTimeServer: public Poco::Util::ServerApplication{
public:
    HTTPTimeServer(): _helpRequested(false){
    }
    ~HTTPTimeServer(){
    }
protected:
    void initialize(Application& self){
      loadConfiguration();
      ServerApplication::initialize(self);
    }
   
    void uninitialize(){
      ServerApplication::uninitialize();
    }
   
    void defineOptions(OptionSet& options){
      ServerApplication::defineOptions(options);
      options.addOption(
        Option("help", "h", "display argument help information")
        .required(false)
        .repeatable(false)
        .callback(OptionCallback<HTTPTimeServer>(
         this, &HTTPTimeServer::handleHelp)));
    }
   
    void handleHelp(const std::string& name,
        const std::string& value){
      HelpFormatter helpFormatter(options());
      helpFormatter.setCommand(commandName());
      helpFormatter.setUsage("OPTIONS");
      helpFormatter.setHeader("A web server that serves the current date and time.");
      helpFormatter.format(std::cout);
      stopOptionsProcessing();
      _helpRequested = true;
    }
   
    int main(const std::vector<std::string>& args){
      if (!_helpRequested){
        unsigned short port = (unsigned short)
        config().getInt("HTTPTimeServer.port", 9980);
        std::string format(config().getString("HTTPTimeServer.format",DateTimeFormat::SORTABLE_FORMAT));
        ServerSocket svs(port);
        HTTPServer srv(new TimeRequestHandlerFactory(format),
        svs, new HTTPServerParams);
        srv.start();
        waitForTerminationRequest();
        srv.stop();   
      }
    return Application::EXIT_OK;
}
private:
    bool _helpRequested;
};

int main(int argc, char** argv){
HTTPTimeServer app;
return app.run(argc, argv);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章