概要介绍
POCO C++是一个开源的C++类库的集合,它主要提供简单的、快速的网络和可移植应用程序的C++开发,这个类库和C++标准库可以很好的集成并填补C++标准库的功能空缺。POCO库的模块化、高效的设计及实现使得POCO特别适合嵌入式开发
二、模块说明
POCO由4个核心库及若干个附加库组成。核心库是:Foundation、XML、Util和Net。其中的两个附加库是:NetSSL,为Net 库中的网络类提供SSL 支持;Data,用来以统一的形式访问不同的SQL 数据库。POCO致力于进行以网络功能为核心的跨平台C++软件的开发,可以类比于Ruby on Rails对于Web开发的作用——一个功能强大而又简单易用的平台,用来构建妳自己的应用程序。POCO是严格围绕标准ANSI/ISO C++来开发的,并且支持标准库。贡献者们努力地达到以下要素之间的平衡:使用高级的C++特性;保持那些类的可理解性;保持代码的干净、一致及易维护性。
- 线程
Poco实现线程的机制,它将线程Thread和线程运行的实体Runnable分离开来,就像一个框架,Thread管理线程优先级,堆栈,维护线程局部变量;而运行的代码是在Runnable的子类run方法中实现的。
#include "Poco/Thread.h"
#include "Poco/Runnable.h"
#include <iostream>
class HelloRunnable: public Poco::Runnable
{
virtual void run()
{
std::cout << "Hello, bingzhe!" << std::endl;
}
};
int main(int argc, char** argv)
{
HelloRunnable runnable;
Poco::Thread thread;
thread.start(runnable);
thread.join();
return 0;
}
- 线程池
线程池初始化可以设置最少线程数和最多线程数。每次start使用一个线程,超出最大线程数后会有异常。
#include "Poco/ThreadPool.h"
#include "Poco/Runnable.h"
#include <iostream>
class HelloRunnable: public Poco::Runnable
{
virtual void run()
{
std::cout << "Hello, bingzhe" << std::endl;
}
};
int main(int argc, char** argv)
{
Poco::ThreadPool pool(3, 6);//最少2个线程,最多6个线程
HelloRunnable runnable;
if( pool.available() > 0 )
{
pool.start(runnable);
}
pool.joinAll();
return 0;
}
- 内存池
内存池内部使用block数组实现,每次获取到一个block,初始化时可以设置block大小。
#include "Poco/MemoryPool.h"
#include <string>
#include <iostream>
using Poco::MemoryPool;
int main(int argc, char** argv)
{
MemoryPool pool(1024); // unlimited number of 1024 byte blocks
char* buffer = reinterpret_cast<char*>(pool.get());
std::cin.read(buffer, pool.blockSize());
std::streamsize n = std::cin.gcount();
std::string s(buffer, n);
pool.release(buffer);
std::cout << s << std::endl;
return 0;
}
- 日志
日志模块对日志经过一系列channel过滤,最后写入文件。FormattingChannel对日志进行格式化,Channel对日志进行管理和输出。
1. 控制台日志
#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;
}
- 文件日志
FileChannel属性说明:
Path:指明日志文件名
Rotation:指明日志文件控制策略,如按文件大小管理日志文件,超过一定大小后会生成新的文件。
Archive:指明日志文件命名和压缩策略。
#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;
}
- HTTP
- http server
实现HTTPRequestHandler和HTTPRequestHandlerFactory,创建HttpServer时创建HTTPRequestHandlerFactory对象,在HTTPRequestHandlerFactory中处理请求时创建与请求对应的HTTPRequestHandler处理器。
#include <Poco/Net/HTTPServer.h>
#include <Poco/Net/TCPServer.h>
#include <Poco/Net/TCPServerConnectionFactory.h>
#include "Poco/Net/DNS.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/SocketStream.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/SocketStream.h"
#include "Poco/StreamCopier.h"
#include <Poco/Net/HTTPServerParams.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPRequestHandler.h>
#include <Poco/Net/HTTPServerResponse.h>
#include <iostream>
using Poco::Net::DNS;
using Poco::Net::IPAddress;
using Poco::Net::HostEntry;
class RootHandler: public Poco::Net::HTTPRequestHandler
{
public:
void handleRequest(Poco::Net::HTTPServerRequest& request,
Poco::Net::HTTPServerResponse& response)
{
response.setChunkedTransferEncoding(true);
response.setContentType("text/html");
std::ostream& ostr = response.send();
ostr << "<html><head><title>HTTP Server powered by POCO C++ Libraries</title></head>";
ostr << "<body>";
ostr << "<h1>hello</h1>";
ostr << "</body></html>";
}
};
class MyRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory{
public:
MyRequestHandlerFactory(){};
~MyRequestHandlerFactory(){};
public:
virtual Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request)
{
return new RootHandler;
};
};
int main(int argc, char** argv)
{
Poco::UInt16 port = 1080;
Poco::Net::HTTPServerParams * pParams = new Poco::Net::HTTPServerParams;
pParams->setMaxQueued(100);
pParams->setMaxThreads(16);
Poco::Net::ServerSocket svs(port); // set-up a server socket
Poco::Net::HTTPServer srv(new MyRequestHandlerFactory(), svs, pParams);
// start the HTTPServer
srv.start();
//waitForTerminationRequest();
getchar();
// Stop the HTTPServer
srv.stop();
return 0;
}
- HTTP Get
HTTPClientSession 表示http session,HTTPRequest 表示http请求,HTTPResponse 表示http响应。
#include "Poco/JSON/Parser.h"
#include "Poco/JSON/ParseHandler.h"
#include "Poco/JSON/JSONException.h"
#include "Poco/StreamCopier.h"
#include "Poco/Dynamic/Var.h"
#include "Poco/JSON/Query.h"
#include "Poco/JSON/PrintHandler.h"
#include "Poco/Net/HTTPClientSession.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/StreamCopier.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/HTMLForm.h"
#include "Poco/URI.h"
#include <iostream>
using namespace Poco::Dynamic;
using namespace Poco;
using std::string;
using namespace Poco::JSON;
using namespace Poco::Net;
int main()
{
try {
std::string strUrl("http://10.0.1.77:8999/blacklist?id=132623198111196400");
Poco::URI uri(strUrl);
HTTPClientSession session(uri.getHost(), uri.getPort());
HTTPRequest request(HTTPRequest::HTTP_GET, uri.getPathAndQuery());
session.sendRequest(request);
HTTPResponse response;
std::istream &is = session.receiveResponse(response);
const HTTPResponse::HTTPStatus &status = response.getStatus();
if (HTTPResponse::HTTPStatus::HTTP_OK == status) {
std::string result;
StreamCopier::copyToString(is, result);
std::cout << result << result.size() << std::endl;
} else {
std::cout << status << std::endl;
}
} catch (Poco::Exception &e) {
std::cout << e.message() << std::endl;
}
return 0;
}
- HTTP Post
HTTPClientSession 表示http session,HTTPRequest 表示http请求,HTTPResponse 表示http响应,HTMLForm 表示表单。
#include <iostream>
#include <string>
#include "Poco/Net/HTTPClientSession.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/StreamCopier.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/HTMLForm.h"
#include "Poco/URI.h"
int main()
{
try{
URI url("http://test.xheart.cn/xheartdevelop05/user/login/validate");
HTTPClientSession session(url.getHost(),url.getPort());
HTTPRequest request(HTTPRequest::HTTP_POST,url.getPath(),HTTPRequest::HTTP_1_1);
HTMLForm form;
form.add("userName", "1220002");
form.add("password", "1234567");
form.prepareSubmit(request);
form.write(session.sendRequest(request));
HTTPResponse res;
std::istream & is = session.receiveResponse(res);
StreamCopier::copyStream(is, std::cout);
}
catch(NetException & ex){
std::cout << ex.displayText();
}
}
- Websocket
- Server
实现HTTPRequestHandler和HTTPRequestHandlerFactory,创建HttpServer时创建HTTPRequestHandlerFactory对象,在HTTPRequestHandlerFactory中处理请求时创建与请求对应的HTTPRequestHandler处理器。
#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/Net/WebSocket.h"
#include "Poco/Net/NetException.h"
#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include "Poco/Format.h"
#include <iostream>
using Poco::Net::ServerSocket;
using Poco::Net::WebSocket;
using Poco::Net::WebSocketException;
using Poco::Net::HTTPRequestHandler;
using Poco::Net::HTTPRequestHandlerFactory;
using Poco::Net::HTTPServer;
using Poco::Net::HTTPServerRequest;
using Poco::Net::HTTPResponse;
using Poco::Net::HTTPServerResponse;
using Poco::Net::HTTPServerParams;
using Poco::Timestamp;
using Poco::ThreadPool;
using Poco::Util::ServerApplication;
using Poco::Util::Application;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;
class PageRequestHandler: public HTTPRequestHandler
/// Return a HTML document with some JavaScript creating
/// a WebSocket connection.
{
public:
void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
response.setChunkedTransferEncoding(true);
response.setContentType("text/html");
std::ostream& ostr = response.send();
ostr << "<html>";
ostr << "<head>";
ostr << "<title>WebSocketServer</title>";
ostr << "<script type=\"text/javascript\">";
ostr << "function WebSocketTest()";
ostr << "{";
ostr << " if (\"WebSocket\" in window)";
ostr << " {";
ostr << " var ws = new WebSocket(\"ws://" << request.serverAddress().toString() << "/ws\");";
ostr << " ws.onopen = function()";
ostr << " {";
ostr << " ws.send(\"Hello, world!\");";
ostr << " };";
ostr << " ws.onmessage = function(evt)";
ostr << " { ";
ostr << " var msg = evt.data;";
ostr << " alert(\"Message received: \" + msg);";
ostr << " ws.close();";
ostr << " };";
ostr << " ws.onclose = function()";
ostr << " { ";
ostr << " alert(\"WebSocket closed.\");";
ostr << " };";
ostr << " }";
ostr << " else";
ostr << " {";
ostr << " alert(\"This browser does not support WebSockets.\");";
ostr << " }";
ostr << "}";
ostr << "</script>";
ostr << "</head>";
ostr << "<body>";
ostr << " <h1>WebSocket Server</h1>";
ostr << " <p><a href=\"javascript:WebSocketTest()\">Run WebSocket Script</a></p>";
ostr << "</body>";
ostr << "</html>";
}
};
class WebSocketRequestHandler: public HTTPRequestHandler
/// Handle a WebSocket connection.
{
public:
void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
Application& app = Application::instance();
try
{
WebSocket ws(request, response);
app.logger().information("WebSocket connection established.");
char buffer[1024];
int flags;
int n;
do
{
n = ws.receiveFrame(buffer, sizeof(buffer), flags);
app.logger().information(Poco::format("Frame received (length=%d, flags=0x%x).", n, unsigned(flags)));
ws.sendFrame(buffer, n, flags);
}
while (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE);
app.logger().information("WebSocket connection closed.");
}
catch (WebSocketException& exc)
{
app.logger().log(exc);
switch (exc.code())
{
case WebSocket::WS_ERR_HANDSHAKE_UNSUPPORTED_VERSION:
response.set("Sec-WebSocket-Version", WebSocket::WEBSOCKET_VERSION);
// fallthrough
case WebSocket::WS_ERR_NO_HANDSHAKE:
case WebSocket::WS_ERR_HANDSHAKE_NO_VERSION:
case WebSocket::WS_ERR_HANDSHAKE_NO_KEY:
response.setStatusAndReason(HTTPResponse::HTTP_BAD_REQUEST);
response.setContentLength(0);
response.send();
break;
}
}
}
};
class RequestHandlerFactory: public HTTPRequestHandlerFactory
{
public:
HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request)
{
Application& app = Application::instance();
app.logger().information("Request from "
+ request.clientAddress().toString()
+ ": "
+ request.getMethod()
+ " "
+ request.getURI()
+ " "
+ request.getVersion());
for (HTTPServerRequest::ConstIterator it = request.begin(); it != request.end(); ++it)
{
app.logger().information(it->first + ": " + it->second);
}
if(request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0)
return new WebSocketRequestHandler;
else
return new PageRequestHandler;
}
};
int main(int argc, char** argv)
{
Poco::UInt16 port = 1080;
Poco::Net::HTTPServerParams * pParams = new Poco::Net::HTTPServerParams;
pParams->setMaxQueued(100);
pParams->setMaxThreads(16);
Poco::Net::ServerSocket svs(port); // set-up a server socket
Poco::Net::HTTPServer srv(new RequestHandlerFactory(), svs, pParams);
// start the HTTPServer
srv.start();
//waitForTerminationRequest();
getchar();
// Stop the HTTPServer
srv.stop();
return 0;
}
- Client
和Http client类似,增加了一个WebSocket类来处理websocket数据。
#include <iostream>
#include <Poco/Net/WebSocket.h>
#include <Poco/Net/HTTPClientSession.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/Net/ServerSocket.h>
#include <Poco/Net/NetException.h>
#include <Poco/Exception.h>
using Poco::Net::HTTPClientSession;
using Poco::Net::HTTPRequest;
using Poco::Net::HTTPResponse;
using Poco::Net::HTTPServerRequest;
using Poco::Net::HTTPServerResponse;
using Poco::Net::WebSocket;
using Poco::Net::WebSocketException;
using Poco::Exception;
using namespace std;
int main()
{
char buffer[1024];
int flags;
int n;
std::string payload;
try {
HTTPClientSession cs("echo.websocket.org", 80);
HTTPRequest request(HTTPRequest::HTTP_GET, "/", "HTTP/1.1");
HTTPResponse response;
std::string cmd;
WebSocket * ws = new WebSocket(cs, request, response); // Causes the timeout
payload = "SGClient: Hello World!";
cout << "Send: SGClient: Hello World!" << endl;
ws->sendFrame(payload.data(), payload.size(), WebSocket::FRAME_TEXT);
n = ws->receiveFrame(buffer, sizeof(buffer), flags);
buffer[n] = '\0';
cout << "Received: " << buffer << endl;
while (cmd != "exit") {
cmd = "";
cout << "Please input[exit]:";
std::cin >> cmd;
ws->sendFrame(cmd.data(), cmd.size(), WebSocket::FRAME_TEXT);
n = ws->receiveFrame(buffer, sizeof(buffer), flags);
buffer[n] = '\0';
if (n > 0) {
std::cout << "Receive: " << buffer << std::endl;
}
}
ws->shutdown();
} catch (Exception ex) {
cout << ex.displayText() << endl;
cout << ex.what() << endl;
return -1;
}
}
- 数据库
数据库操作首先要注册相应的Connector,Session类管理数据库和表,Statement类对表记录进行操作。
- SQLite
#include "Poco/SharedPtr.h"
#include "Poco/Tuple.h"
#include "Poco/Data/SessionFactory.h"
#include "Poco/Data/Session.h"
#include "Poco/Data/SQLite/Connector.h"
#include <vector>
#include <iostream>
using namespace Poco::Data::Keywords;
using Poco::Data::Session;
using Poco::Data::Statement;
int main(int argc, char** argv)
{
typedef Poco::Tuple<std::string, std::string, int> Person;
typedef std::vector<Person> People;
// register SQLite connector
Poco::Data::SQLite::Connector::registerConnector();
// create a session
Session session("SQLite", "sample.db");
// drop sample table, if it exists
session << "DROP TABLE IF EXISTS Person", now;
// (re)create table
session << "CREATE TABLE Person (Name VARCHAR(30), Address VARCHAR, Age INTEGER(3))", now;
// insert some rows
People people;
people.push_back(Person("Bart Simpson", "Springfield", 12));
people.push_back(Person("Lisa Simpson", "Springfield", 10));
Statement insert(session);
insert << "INSERT INTO Person VALUES(:name, :address, :age)",
use(people), now;
people.clear();
// a simple query
Statement select(session);
select << "SELECT Name, Address, Age FROM Person",
into(people),
now;
for (People::const_iterator it = people.begin(); it != people.end(); ++it)
{
std::cout << "Name: " << it->get<0>() <<
", Address: " << it->get<1>() <<
", Age: " << it->get<2>() <<std::endl;
}
return 0;
}
- JSON
格式化JSON使用JSON::Object 类,JSON解析使用JSON::Parser类。使用Dynamic::Var类对JSON对象和变量进行类型转换操作。
#include <iostream>
#include "Poco/Dynamic/Var.h"
#include "Poco/Dynamic/Pair.h"
#include "Poco/Dynamic/VarIterator.h"
#include "Poco/JSON/Array.h"
#include <vector>
#include <map>
#include "Poco/JSON/Parser.h"
using Poco::Dynamic::Var;
using Poco::JSON::Parser;
using Poco::Dynamic::Pair;
using Poco::JSON::Array;
using Poco::JSON::Object;
int main(int argc, const char * argv[])
{
using namespace std;
Poco::JSON::Object scores;
scores.set("数学", 98);
scores.set("英语", 99);
scores.set("语文", 89);
scores.set("化学", 100);
scores.set("物理", 98);
scores.set("生物", 96);
Poco::JSON::Object student;
student.set("name", "小南");
student.set("address", "四川省成都市锦江区锦华路一段7号爱家丽苑1栋1单元305室");
student.set("class", "四川省成都市第七中学2010级2班");
student.set("grade", Poco::Dynamic::Var(scores));
Poco::Dynamic::Var JSON(student);
cout << JSON.toString() << endl;
string theJSON = JSON.toString();
Poco::JSON::Parser parser;
Poco::Dynamic::Var json = parser.parse(theJSON);
Poco::JSON::Object theObj = *json.extract<Poco::JSON::Object::Ptr>();
Poco::Dynamic::Var theScores = theObj.get("grade");
Poco::Dynamic::Var name = theObj.get("name");
Poco::Dynamic::Var address = theObj.get("address");
Poco::Dynamic::Var theClass = theObj.get("class");
Poco::JSON::Object grade = *theScores.extract<Poco::JSON::Object::Ptr>();
Poco::Dynamic::Var math = grade.get("数学");
Poco::Dynamic::Var english = grade.get("英语");
Poco::Dynamic::Var chinese = grade.get("语文");
Poco::Dynamic::Var wuli = grade.get("物理");
Poco::Dynamic::Var shengwu = grade.get("生物");
Poco::Dynamic::Var huaxue = grade.get("化学");
cout << "\n\n姓名: " << name.toString() << endl
<< "班级: " << theClass.toString() << endl
<< "地址: " << address.toString() << endl
<< "数学: " << math.convert<int>() << endl
<< "语文: " << chinese.convert<int>() << endl
<< "化学: " << huaxue.convert<int>() << endl
<< "物理: " << wuli.convert<int>() << endl
<< "生物: " << shengwu.convert<int>() << endl;
return 0;
}
- XML
- 格式化XML
#include "Poco/DOM/Document.h"
#include "Poco/DOM/Element.h"
#include "Poco/DOM/Text.h"
#include "Poco/DOM/AutoPtr.h"
#include "Poco/DOM/DOMWriter.h"
#include "Poco/XML/XMLWriter.h"
#include <iostream>
using Poco::XML::Document;
using Poco::XML::Element;
using Poco::XML::Text;
using Poco::XML::AutoPtr;
using Poco::XML::DOMWriter;
using Poco::XML::XMLWriter;
int main(int argc, char** argv)
{
// build a DOM document and write it to standard output.
AutoPtr<Document> pDoc = new Document;
AutoPtr<Element> pRoot = pDoc->createElement("root");
pDoc->appendChild(pRoot);
AutoPtr<Element> pChild1 = pDoc->createElement("child1");
AutoPtr<Text> pText1 = pDoc->createTextNode("text1");
pChild1->appendChild(pText1);
pRoot->appendChild(pChild1);
AutoPtr<Element> pChild2 = pDoc->createElement("child2");
AutoPtr<Text> pText2 = pDoc->createTextNode("text2");
pChild2->appendChild(pText2);
pRoot->appendChild(pChild2);
DOMWriter writer;
writer.setNewLine("\n");
writer.setOptions(XMLWriter::PRETTY_PRINT);
writer.writeNode(std::cout, pDoc);
return 0;
}
- 解析XML
/*
配置文件,名称test.xml
<config>
<prop1>value1</prop1>
<prop2>123</prop2>
<prop3>
<prop4 attr="value3" />
<prop4 attr="value4" />
</prop3>
</config>
*/
#include "Poco/AutoPtr.h"
#include "Poco/Util/XMLConfiguration.h"
#include <iostream>
using namespace std;
using Poco::AutoPtr;
using Poco::Util::XMLConfiguration;
int main(int argc, char** argv)
{
AutoPtr<XMLConfiguration> pConfig(new XMLConfiguration("test.xml"));
std::string prop1 = pConfig->getString("prop1");
cout << prop1 << endl;
int prop2 = pConfig->getInt("prop2");
cout << prop2 << endl;
std::string prop3 = pConfig->getString("prop3");
cout << prop3 << endl;
std::string prop4 = pConfig->getString("prop3.prop4");
cout << prop4 << endl;
prop4 = pConfig->getString("prop3.prop4[@attr]");
cout << prop4 << endl;
prop4 = pConfig->getString("prop3.prop4[1][@attr]");
cout << prop4 << endl;
return 0;
}