Poco::Net提供了很多便利的开发组件。尽管Poco目前还不是一个很完美的C++类库,但是它从设计上和使用的简易程度上都有着较为超前的理念。

大概是去年年底,我开始使用Poco::Net封装的网络通信库取代了boost::asio,直至现在Poco的文档也并不多,不过使用方法很有套路性。Poco封装的组件可以说已经把开发者绑死在了这种固定的使用模式上,因此可以很轻易地搭建一个TCPServer并且跑起来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
struct ServiceApplicationParams
{
std::string listen_address;
int max_queued;
int max_threads;
};
class ServiceApplication
: public Poco::Util::ServerApplication
{
public:
ServiceApplication(const std::string& serviceName, MessageDispatcher* messageDispatcher);
virtual ~ServiceApplication();
public:
int run(int argc, char** argv, Venus::ServiceApplicationParams* params);
int main(const std::vector<std::string>& args);
virtual void defineOptions(Poco::Util::OptionSet& options);
virtual void handleOption(const std::string& name, const std::string& value);
private:
void initialize(Poco::Util::Application& self);
void uninitialize();
private:
Venus::ServiceApplicationParams* _applicationParams;
Poco::Net::SocketReactor _reactor;
MessageQueue _messageQueue;
std::string _serviceName;
};

写过服务器应用的都知道,相比起使用平台自带的Native Socket Api而言,上面的代码充满了现代C++感,可读性很好。首先我们把服务进程抽象为一个Application,这也是由继承Poco::Util::ServerApplication开始的。它提供了run()方法作为启动入口。根据这种设计,我们也可以把服务编译为动态库,以组件的形式提供给service box,从外部启动。

要启用一个TCPServer也相当简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Poco::Net::SocketAddress listenAddress(_applicationParams->listen_address);
Poco::Net::ServerSocket socket(listenAddress);
Poco::Net::TCPServerParams* serverParams = new Poco::Net::TCPServerParams();
serverParams->setMaxQueued(_applicationParams->max_queued);
serverParams->setMaxThreads(_applicationParams->max_threads);
MessageQueueWorker queueWorker(_messageQueue);
Poco::ThreadPool::defaultPool().start(queueWorker);
ConnectionFactory connectionFactory;
connectionFactory.setMessageQueue(_messageQueue);
Poco::Net::TCPServer server(&connectionFactory, socket, serverParams);
server.start();
info_log("Server started.");
Poco::Util::ServerApplication::waitForTerminationRequest();
_messageQueue.wakeUpAll();
server.stop();

和传统做法一样,我们需要提供一个监听端口以及Socket. 与传统做法不一样的是,Poco给我们提供了一个Reactor,基于事件驱动。每当有新的连接产生时,便会从ConnectionFactory中创建一个Poco::Net::TCPServerConnection的实例。之后的工作,就交给消息队列处理,至于回调到上层的工作,自然也是通过消息队列分发出去。

Poco的代码易读易懂,但在这段时间的使用中,仍然遇到了Poco的不少小坑,包括Poco::Net和Poco::Data,存在一些不完美的设计缺陷。相信这些问题以后会得到很好的解决。

以上代码摘自Venus:https://github.com/AngryPowman/Coeus/tree/master/src/coeus/venus_net