POCO库中文编程参考指南(10)如何使用TCPServer框架?

简介: 1 TCPServer 框架概述 POCO 库提供TCPServer框架,用以搭建自定义的 TCP 服务器。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()waitForTerminationRequeststop()就行了。

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;
}

-

from:Blog.CSDN.net/Poechant

目录
相关文章
|
12月前
|
安全 关系型数据库 MySQL
如何将数据从MySQL同步到其他系统
【10月更文挑战第17天】如何将数据从MySQL同步到其他系统
1566 0
|
关系型数据库 MySQL 开发工具
windows编译poco c++库
windows编译poco c++库
|
算法 C语言 C++
C++ std::chrono库使用指南 (实现C++ 获取日期,时间戳,计时等功能)(一)
C++ std::chrono库使用指南 (实现C++ 获取日期,时间戳,计时等功能)
4278 1
|
Python 数据格式 XML
深入python3 (Dive Into Python 3) 在线阅读与下载
在线阅读:http://book.doucube.com/diveintopython3/  中文版 下载地址:https://github.com/downloads/diveintomark/diveintopython3/dive-into-python3.
3300 0
关于 QtCreator中写Qt程序遇到printf不输出问题 的解决方法
关于 QtCreator中写Qt程序遇到printf不输出问题 的解决方法
|
10月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
725 14
|
监控 Linux Shell
|
数据处理
正则表达式详解:解析星号的含义
【4月更文挑战第3天】
1793 1
正则表达式详解:解析星号的含义
【Java基础】建立一个双向链表(增删查改)
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
219 0
|
缓存 Python
研发提效工具1 - 秒级二维码生成方案
# 背景 我们在日常工作和开发过程中,有时会有生成二维码的需求。 一般的生成二维码路径是: 1. 打开浏览器 2. 通过搜索或书签进入某二维码生成网站(如[草料](https://cli.im/)) 3. 输入带生成的文本 4. 点击生成 这种生成二维码的链路比较繁琐和冗长,本文介绍另一种更高效的方式来完成二维码的生成操作。 # 效果图 ![](https://ata2-im
360 0
研发提效工具1 - 秒级二维码生成方案