1 TCPServer 框架概述

POCO 库提供TCPServer框架,用以搭建自定义的 TCP 服务器。TCPServer维护一个连接队列、一个连接线程池。连接线程用于处理连接,连接线程只要一空闲就不断地从连接队列中取连接并进行处理。一旦连接线程从连接队列中取到一个连接,就会创建一个TCPServerConnection连接对象,并且调用该对象的start()方法,直到start()方法返回,这个连接对象就被删除了。

连接线程的数量是动态的,其取决于连接队列中排队的连接数。当然,你使用的时候可以设定连接队列的最大容量,以防止在高并发应用的服务器上出现连接太多而使连接队列溢出的悲剧发生。当连接队列满了,却还有新的连接到来时,新来的连接就会被立即悄无声息地关闭。

现在我们总结一下,就是要有一个可运行的 TCP 服务应用程序(命名为PoechantTCPServer),还有很多 TCP 连接(命名为PoechantTCPConnection)。而这里我们用到工厂模式(准确说是TCPServerConnectionFactory要我们用的),所以还有一个 PoechantTCPConnectionFactory

2 光说不练假把式

2.1 创建一个 PoechantTCPServer

或许你还不熟悉 POCO 中的 Application,没关系,这不影响本文的叙述。下面先创建一个 ServerApplication 如下:

  1. // PoechantTCPServer.h
  2. #ifndef POECHANT_TCP_SERVER
  3. #define POECHANT_TCP_SERVER
  4. #include "Poco/Util/ServerApplication.h"
  5. #include "Poco/Util/Application.h"
  6. using Poco::Util::ServerApplication;
  7. using Poco::Util::Application;
  8. class PoechantTCPServer: public ServerApplication
  9. {
  10. public:
  11. PoechantTCPServer() {}
  12. ~PoechantTCPServer() {}
  13. protected:
  14. void initialize(Application& self);
  15. void uninitialize();
  16. int main(const std::vector<std::string>& args)
  17. };
  18. #endif

这样在调用启动PoechantTCPServer时,会先调用initialize,然后调用main,在main结束后会调用uninitialize。其实现很简单:

  1. // PoechantTCPServer.cpp
  2. #include "PoechantTCPServer.h"
  3. void PoechantTCPServer::initialize(Application& self)
  4. {
  5. ServerApplication::loadConfiguration();
  6. ServerApplication::initialize(self);
  7. }
  8. void PoechantTCPServer::uninitialize()
  9. {
  10. ServerApplication::uninitialize();
  11. }
  12. int PoechantTCPServer::main(const std::vector<std::string>& args)
  13. {
  14. // 这个咱最后说
  15. return Application::EXIT_OK;
  16. }

2.2 PoechantTCPConnection

连接类的定义很简单,构造函数要传入一个 StreamSocket 和其他你需要的参数。

  1. // PoechantTCPConnection.h
  2. #ifndef POECHANT_TCP_CONNECTION_H
  3. #define POECHANT_TCP_CONNECTION_H
  4. #include "Poco/Net/TCPServerConnection.h"
  5. #include "Poco/Net/StreamSocket.h"
  6. #include <string>
  7. class PoechantTCPConnection: public TCPServerConnection
  8. {
  9. public:
  10. PoechantTCPConnection(const StreamSocket& s,
  11. const std::string& arg1,
  12. int arg2,
  13. double arg3);
  14. void run();
  15. private:
  16. std::string _arg1;
  17. int _arg2;
  18. double _arg3;
  19. };
  20. #endif

实现如下:

  1. // PoechantTCPConnection.cpp
  2. #include "PoechantTCPConnection.h"
  3. #include "Poco/Util/Application"
  4. #include "Poco/Timestamp.h"
  5. #include "Poco/Exception.h"
  6. #include "Poco/DateTimeFormatter.h"
  7. PoechantTCPConnection(const StreamSocket& s, const std::string& arg1, int arg2, double arg3):
  8. TCPServerConnection(s), _arg1(arg1), _arg2(arg2), _arg3(arg3)
  9. {
  10. }
  11. void run()
  12. {
  13. Application& app = Application::instance();
  14. // 日志输出连接的TCP用户的地址(IP和端口)
  15. app.logger().information("Request from " + this->socket().peerAddress().toString());
  16. try
  17. {
  18. // 向客户端发送数据,这里以发送一个表示时间的字符串为例
  19. Timestamp now;
  20. std::string dt(DateTimeFormatter::format(now, _format));
  21. dt.append("\r\n");
  22. socket().sendBytes(dt.data(), (int) dt.length());
  23. }
  24. catch (Poco::Exception& e)
  25. {
  26. app.logger().log(e);
  27. }
  28. }

2.3 PoechantTCPConnectionFactory

工厂模式不必多说,名字唬人,其实非常非常简单(准确的说设计模式大部分名字都唬人,但大部分都很有用,设计模式本身并不牛B,能把设计模式抽象提炼出来成我们现在认为很简单的这些模式的那几个人很牛B)。具体如下:

  1. // PoechantTCPConnectionFactory.h
  2. #ifndef POECHANT_TCP_CONNECTION_FACTORY_H
  3. #define POECHANT_TCP_CONNECTION_FACTORY_H
  4. #include "Poco/Net/TCPServerConnectionFactory.h"
  5. #include "Poco/Net/TCPServerConnection.h"
  6. #include "Poco/Net/StreamSocket.h"
  7. #include <string>
  8. class PoechantTCPConnectionFactory: public TCPServerConnectionFactory
  9. {
  10. public:
  11. PoechantTCPConnectionFactory(const std::string arg1, int arg2, double arg3)
  12. : _arg1(arg1), _arg2(arg2), _arg3(arg3)
  13. {
  14. }
  15. TCPServerConnection* createConnection(const StreamSocket& socket)
  16. {
  17. return new PoechantTCPConnection(socket, arg1, arg2, arg3);
  18. }
  19. private:
  20. std::string arg1;
  21. int arg2;
  22. double arg3;
  23. };
  24. #endif

2.4 启动

回头来说PoechantTCPServer::main(const std::vector<std::string>& args),其过程就是创建一个绑定了地址的ServerSocket,把它传给TCPServer,当然别忘了把工程对象也给你的TCPServer传一个。最后就start()waitForTerminationRequeststop()就行了。

  1. int PoechantTCPServer::main(const std::vector<std::string>& args)
  2. {
  3. unsigned short port = (unsigned short) config().getInt("PoechantTCPServer.port", 12346);
  4. std::string format(config().getString("PoechantTCPServer.format",
  5. DateTimeFormat::ISO8601_FORMAT));
  6. // 1. Bind a ServerSocket with an address
  7. ServerSocket serverSocket(port);
  8. // 2. Pass the ServerSocket to a TCPServer
  9. TCPServer server(new PoechantTCPConnectionFactory(format), serverSocket);
  10. // 3. Start the TCPServer
  11. server.start();
  12. // 4. Wait for termination
  13. waitForTerminationRequest();
  14. // 5. Stop the TCPServer
  15. server.stop();
  16. return Application::EXIT_OK;
  17. }

然后写一个程序入口:

  1. #include "PoechantTCPServer.h"
  2. int main(int argc, char **argv)
  3. {
  4. return PoechantTCPServer().run(argc, argv);
  5. }

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 循环,其实可以在收到数据后就关闭的)

  1. #include <iostream>
  2. #include "Poco/Net/StreamSocket.h"
  3. #include "Poco/Net/SocketAddress.h"
  4. #define BUFFER_SIZE 1024
  5. using Poco::Net::SocketAddress;
  6. using Poco::Net::StreamSocket;
  7. int main (int argc, const char * argv[])
  8. {
  9. SocketAddress address("127.0.0.1", 12346);
  10. StreamSocket socket(address);
  11. char buffer[BUFFER_SIZE];
  12. while (true)
  13. {
  14. if (socket.available())
  15. {
  16. int len = socket.receiveBytes(buffer, BUFFER_SIZE);
  17. buffer[len] = '\0';
  18. std::cout << "" << buffer << std::endl;
  19. }
  20. }
  21. return 0;
  22. }

-

from:Blog.CSDN.net/Poechant

POCO库中文编程参考指南(10)如何使用TCPServer框架?的更多相关文章

  1. POCO库中文编程参考指南(11)如何使用Reactor框架?

    1 Reactor 框架概述 POCO 中的 Reactor 框架是基于 Reactor 设计模式进行设计的.其中由 Handler 将某 Socket 产生的事件,发送到指定的对象的方法上,作为回调 ...

  2. POCO库中文编程参考指南(8)丰富的Socket编程

    POCO库中文编程参考指南(8)丰富的Socket编程 作者:柳大·Poechant 博客:Blog.CSDN.net/Poechant 邮箱:zhongchao.ustc#gmail.com (# ...

  3. POCO库中文编程参考指南(4)Poco::Net::IPAddress

    POCO库中文编程参考指南(4)Poco::Net::IPAddress 作者:柳大·Poechant 博客:Blog.CSDN.net/Poechant 邮箱:zhongchao.ustc#gmai ...

  4. POCO库中文编程参考指南(3)Poco::Net::Socket

    POCO库中文编程参考指南(3)Poco::Net::Socket 作者:柳大·Poechant 博客:Blog.CSDN.net/Poechant 邮箱:zhongchao.ustc#gmail.c ...

  5. POCO库中文编程参考指南(2)基本数据类型(Poco/Types.h)

    POCO库中文编程参考指南(2)基本数据类型 作者:柳大·Poechant 博客:Blog.CSDN.net/Poechant 邮箱:zhongchao.ustc#gmail.com (# -> ...

  6. POCO库中文编程参考指南(1)总览

    POCO库中文编程参考指南(1)总览 作者:柳大·Poechant 博客:Blog.CSDN.net/Poechant 邮箱:zhongchao.ustc#gmail.com (# -> @) ...

  7. POCO库中文编程参考指南(5)Poco::Net::SocketAddress

    1 枚举 最大地址长度,这个与Poco::Net::IPAddress中的定义可以类比,不过这里指的是`struct sockaddr_in6 enum { MAX_ADDRESS_LENGTH = ...

  8. POCO库中文编程参考指南(6)Poco::Timestamp

    1 类型别名 三个时间戳相关的类型别名,TimeDiff表示两个时间戳的差,第二个是以微秒为单位的时间戳,第三个是以 100 纳秒(0.1 微妙)为单位的时间戳: typedef Int64 Time ...

  9. POCO库中文编程参考指南(9)Poco::Net::DNS

    1 Poco::Net::DNS namespace Poco { namespace Net { class Net_API DNS { public: static HostEntry hostB ...

随机推荐

  1. 全命令行手写MapReduce并且打包运行

    主要要讲的有3个 java中的package是干啥的? 工作了好几年的都一定真正理解java里面的package关键字,这里在写MapReduce需要进行打包的时候突然发现命令行下打包运行居然不会了, ...

  2. IPv4(三)地址掩码

    回顾网络类型确定 回顾一下之前学过的如果确定IP地址网络号,这里先不考虑子网. 首先通过首个八位组字节规则很容易确定IP地址属于那个网络: 如果第1位是0,则是A类地址: 如果前两位是10,则是B类地 ...

  3. erlang的timer定时器浅析

    timer作为其计时器: erlang的计时器timer是通过一个唯一的timer进程实现的,该进程是一个gen_server,用户通过timer:send_after和timer:apply_aft ...

  4. VI使用说明 (转)

    vi使用方法(ZT)         vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令.由于对Unix及Lin ...

  5. 浅谈WPF本质中的数据和行为

    WPF缩写为Windows Presentation Foundation的缩写,本文所要谈的就是WPF本质中的数据和行为,希望通过本文能对大家了解WPF本质有所帮助. 如果自己来做一个UI框架,我们 ...

  6. VMware 报错“Intel VT-x处于禁止状态”

    VMware Workstation 10虚拟机安装64位windows server 2008 R2系统时报错“Intel VT-x处于禁止状态”,如下图.   工具/原料   VMware Wor ...

  7. “volatile”这个关键字

    我们经常使用“volatile”这个关键字,它是什么意思? 解析:volatile问题.当一个对象的值可能会在编译器的控制或监测之外被改变时,例如一个被系统时钟更新的变量,那么该对象应该声明成vola ...

  8. 【BZOJ3295】[Cqoi2011]动态逆序对 cdq分治

    [BZOJ3295][Cqoi2011]动态逆序对 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依 ...

  9. 九度OJ 1042:Coincidence(公共子序列) (DP)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2303 解决:1241 题目描述: Find a longest common subsequence of two strings. 输入 ...

  10. TCP/UDP server

    Simple: Sample TCP/UDP server https://msdn.microsoft.com/en-us/library/aa231754(v=vs.60).aspx Simple ...