POCO库中文编程参考指南(10)如何使用TCPServer框架?
1 TCPServer 框架概述
POCO 库提供TCPServer
框架,用以搭建自定义的 TCP 服务器。TCPServer
维护一个连接队列、一个连接线程池。连接线程用于处理连接,连接线程只要一空闲就不断地从连接队列中取连接并进行处理。一旦连接线程从连接队列中取到一个连接,就会创建一个TCPServerConnection
连接对象,并且调用该对象的start()
方法,直到start()
方法返回,这个连接对象就被删除了。
连接线程的数量是动态的,其取决于连接队列中排队的连接数。当然,你使用的时候可以设定连接队列的最大容量,以防止在高并发应用的服务器上出现连接太多而使连接队列溢出的悲剧发生。当连接队列满了,却还有新的连接到来时,新来的连接就会被立即悄无声息地关闭。
现在我们总结一下,就是要有一个可运行的 TCP 服务应用程序(命名为PoechantTCPServer
),还有很多 TCP 连接(命名为PoechantTCPConnection
)。而这里我们用到工厂模式(准确说是TCPServerConnectionFactory
要我们用的),所以还有一个 PoechantTCPConnectionFactory
。
2 光说不练假把式
2.1 创建一个 PoechantTCPServer
或许你还不熟悉 POCO 中的 Application,没关系,这不影响本文的叙述。下面先创建一个 ServerApplication 如下:
// PoechantTCPServer.h
#ifndef POECHANT_TCP_SERVER
#define POECHANT_TCP_SERVER
#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Application.h"
using Poco::Util::ServerApplication;
using Poco::Util::Application;
class PoechantTCPServer: public ServerApplication
{
public:
PoechantTCPServer() {}
~PoechantTCPServer() {}
protected:
void initialize(Application& self);
void uninitialize();
int main(const std::vector<std::string>& args)
};
#endif
这样在调用启动PoechantTCPServer
时,会先调用initialize
,然后调用main
,在main
结束后会调用uninitialize
。其实现很简单:
// PoechantTCPServer.cpp
#include "PoechantTCPServer.h"
void PoechantTCPServer::initialize(Application& self)
{
ServerApplication::loadConfiguration();
ServerApplication::initialize(self);
}
void PoechantTCPServer::uninitialize()
{
ServerApplication::uninitialize();
}
int PoechantTCPServer::main(const std::vector<std::string>& args)
{
// 这个咱最后说
return Application::EXIT_OK;
}
2.2 PoechantTCPConnection
连接类的定义很简单,构造函数要传入一个 StreamSocket 和其他你需要的参数。
// PoechantTCPConnection.h
#ifndef POECHANT_TCP_CONNECTION_H
#define POECHANT_TCP_CONNECTION_H
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/StreamSocket.h"
#include <string>
class PoechantTCPConnection: public TCPServerConnection
{
public:
PoechantTCPConnection(const StreamSocket& s,
const std::string& arg1,
int arg2,
double arg3);
void run();
private:
std::string _arg1;
int _arg2;
double _arg3;
};
#endif
实现如下:
// PoechantTCPConnection.cpp
#include "PoechantTCPConnection.h"
#include "Poco/Util/Application"
#include "Poco/Timestamp.h"
#include "Poco/Exception.h"
#include "Poco/DateTimeFormatter.h"
PoechantTCPConnection(const StreamSocket& s, const std::string& arg1, int arg2, double arg3):
TCPServerConnection(s), _arg1(arg1), _arg2(arg2), _arg3(arg3)
{
}
void run()
{
Application& app = Application::instance();
// 日志输出连接的TCP用户的地址(IP和端口)
app.logger().information("Request from " + this->socket().peerAddress().toString());
try
{
// 向客户端发送数据,这里以发送一个表示时间的字符串为例
Timestamp now;
std::string dt(DateTimeFormatter::format(now, _format));
dt.append("\r\n");
socket().sendBytes(dt.data(), (int) dt.length());
}
catch (Poco::Exception& e)
{
app.logger().log(e);
}
}
2.3 PoechantTCPConnectionFactory
工厂模式不必多说,名字唬人,其实非常非常简单(准确的说设计模式大部分名字都唬人,但大部分都很有用,设计模式本身并不牛B,能把设计模式抽象提炼出来成我们现在认为很简单的这些模式的那几个人很牛B)。具体如下:
// PoechantTCPConnectionFactory.h
#ifndef POECHANT_TCP_CONNECTION_FACTORY_H
#define POECHANT_TCP_CONNECTION_FACTORY_H
#include "Poco/Net/TCPServerConnectionFactory.h"
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/StreamSocket.h"
#include <string>
class PoechantTCPConnectionFactory: public TCPServerConnectionFactory
{
public:
PoechantTCPConnectionFactory(const std::string arg1, int arg2, double arg3)
: _arg1(arg1), _arg2(arg2), _arg3(arg3)
{
}
TCPServerConnection* createConnection(const StreamSocket& socket)
{
return new PoechantTCPConnection(socket, arg1, arg2, arg3);
}
private:
std::string arg1;
int arg2;
double arg3;
};
#endif
2.4 启动
回头来说PoechantTCPServer::main(const std::vector<std::string>& args)
,其过程就是创建一个绑定了地址的ServerSocket
,把它传给TCPServer
,当然别忘了把工程对象也给你的TCPServer
传一个。最后就start()
,waitForTerminationRequest
和stop()
就行了。
int PoechantTCPServer::main(const std::vector<std::string>& args)
{
unsigned short port = (unsigned short) config().getInt("PoechantTCPServer.port", 12346);
std::string format(config().getString("PoechantTCPServer.format",
DateTimeFormat::ISO8601_FORMAT));
// 1. Bind a ServerSocket with an address
ServerSocket serverSocket(port);
// 2. Pass the ServerSocket to a TCPServer
TCPServer server(new PoechantTCPConnectionFactory(format), serverSocket);
// 3. Start the TCPServer
server.start();
// 4. Wait for termination
waitForTerminationRequest();
// 5. Stop the TCPServer
server.stop();
return Application::EXIT_OK;
}
然后写一个程序入口:
#include "PoechantTCPServer.h"
int main(int argc, char **argv)
{
return PoechantTCPServer().run(argc, argv);
}
3 写一个 Client 测测
TCPServer 要用 TCP 的客户端来测试。在 POCO 中有丰富的 Socket,其中 TCP 方式的 Socket 有:
Poco::Net::ServerSocket
Poco::Net::StreamSocket
Poco::Net::DialogSocket
Poco::Net::SecureServerSocket
Poco::Net::SecureStreamSocket
UDP 方式的 Socket 有:
Poco::Net::DatagramSocket
Poco::Net::MulticastSocket
一个 TCP 方式 Client 如下(这里用了 while 循环,其实可以在收到数据后就关闭的)
#include <iostream>
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/SocketAddress.h"
#define BUFFER_SIZE 1024
using Poco::Net::SocketAddress;
using Poco::Net::StreamSocket;
int main (int argc, const char * argv[])
{
SocketAddress address("127.0.0.1", 12346);
StreamSocket socket(address);
char buffer[BUFFER_SIZE];
while (true)
{
if (socket.available())
{
int len = socket.receiveBytes(buffer, BUFFER_SIZE);
buffer[len] = '\0';
std::cout << "" << buffer << std::endl;
}
}
return 0;
}
-
POCO库中文编程参考指南(10)如何使用TCPServer框架?的更多相关文章
- POCO库中文编程参考指南(11)如何使用Reactor框架?
1 Reactor 框架概述 POCO 中的 Reactor 框架是基于 Reactor 设计模式进行设计的.其中由 Handler 将某 Socket 产生的事件,发送到指定的对象的方法上,作为回调 ...
- POCO库中文编程参考指南(8)丰富的Socket编程
POCO库中文编程参考指南(8)丰富的Socket编程 作者:柳大·Poechant 博客:Blog.CSDN.net/Poechant 邮箱:zhongchao.ustc#gmail.com (# ...
- POCO库中文编程参考指南(4)Poco::Net::IPAddress
POCO库中文编程参考指南(4)Poco::Net::IPAddress 作者:柳大·Poechant 博客:Blog.CSDN.net/Poechant 邮箱:zhongchao.ustc#gmai ...
- POCO库中文编程参考指南(3)Poco::Net::Socket
POCO库中文编程参考指南(3)Poco::Net::Socket 作者:柳大·Poechant 博客:Blog.CSDN.net/Poechant 邮箱:zhongchao.ustc#gmail.c ...
- POCO库中文编程参考指南(2)基本数据类型(Poco/Types.h)
POCO库中文编程参考指南(2)基本数据类型 作者:柳大·Poechant 博客:Blog.CSDN.net/Poechant 邮箱:zhongchao.ustc#gmail.com (# -> ...
- POCO库中文编程参考指南(1)总览
POCO库中文编程参考指南(1)总览 作者:柳大·Poechant 博客:Blog.CSDN.net/Poechant 邮箱:zhongchao.ustc#gmail.com (# -> @) ...
- POCO库中文编程参考指南(5)Poco::Net::SocketAddress
1 枚举 最大地址长度,这个与Poco::Net::IPAddress中的定义可以类比,不过这里指的是`struct sockaddr_in6 enum { MAX_ADDRESS_LENGTH = ...
- POCO库中文编程参考指南(6)Poco::Timestamp
1 类型别名 三个时间戳相关的类型别名,TimeDiff表示两个时间戳的差,第二个是以微秒为单位的时间戳,第三个是以 100 纳秒(0.1 微妙)为单位的时间戳: typedef Int64 Time ...
- POCO库中文编程参考指南(9)Poco::Net::DNS
1 Poco::Net::DNS namespace Poco { namespace Net { class Net_API DNS { public: static HostEntry hostB ...
随机推荐
- Spark Streaming和Kafka整合开发指南(一)
Apache Kafka是一个分布式的消息发布-订阅系统.可以说,任何实时大数据处理工具缺少与Kafka整合都是不完整的.本文将介绍如何使用Spark Streaming从Kafka中接收数据,这里将 ...
- 【WPF学习笔记】之如何把数据库里的值读取出来然后显示在页面上:动画系列之(六)(评论处有学习资料及源码)
(应博友们的需要,在文章评论处有源码链接地址,以及WPF学习资料.工具等,希望对大家有所帮助) ...... 承接系列五 上一节讲了,已经把数据保存到数据库并且删除数据,本讲是把已经存在的数据从数据库 ...
- MongoDB水平分片集群(转)
为何需要水平分片 1 减少单机请求数,将单机负载,提高总负载 2 减少单机的存储空间,提高总存空间. 下图一目了然: mongodb sharding 服务器架构 简单注解: 1 mongos 路由进 ...
- webstorm-----eslint的配置和使用
https://blog.csdn.net/qq_29329037/article/details/80100450
- python推荐系统库
Python推荐系统库——Surprise 在Python中实现你自己的推荐系统 python-recsys:一款实现推荐系统的python库
- 基于EasyNVR+EasyDSS H5视频直播二次开发实现业务需求:直接使用播放页面
之前的"网页直播.微信直播技术解决方案:EasyNVR与EasyDSS流媒体服务器组合之区分不同场景下的easynvr"有介绍一些功能.由于客户需求,我们定制一下功能.给该套方案添 ...
- AWS:4.VPC
主要介绍 1.Amazon混合云 2.将EC2加入VPC 3.VPC经典场景 4.VPC安全保障 Amazon混合云 : 在公有云的基础上创建私有云 VPC概念 VPC(VPC Virtual Pri ...
- 【题解】HNOI2013比赛
[题解][P3230 HNOI2013]比赛 将得分的序列化成样例给的那种表格,发现一行和一列是同时确定的.这个表格之前是正方形的,后来长宽都减去一,还是正方形.问题形式是递归的.这就启示我们可以把这 ...
- Wireshark学习笔记——怎样高速抓取HTTP数据包
0.前言 在火狐浏览器和谷歌浏览器中能够很方便的调试network(抓取HTTP数据包),可是在360系列浏览器(兼容模式或IE标准模式)中抓取HTTP数据包就不那么那么方便了.尽管也可使用H ...
- Java for LeetCode 119 Pascal's Triangle II
Given an index k, return the kth row of the Pascal's triangle. For example, given k = 3, Return [1,3 ...