C++ Poco::Net 服务器和客户端 TCP 连接事件处理程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14632341/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Poco::Net Server & Client TCP Connection Event Handler
提问by ?lex
I am starting a new project and at the same time have just discovered Poco Library, which I find absolutely amazing. However I am a bit lost, as examples are not plenty.
我正在开始一个新项目,同时刚刚发现了 Poco 图书馆,我觉得这绝对是惊人的。但是我有点迷茫,因为例子并不多。
I have a ServerApplication->TCPServer->ServerSocket + TCPServerConnectionFactory->TCPServerconnection approach as indicated by the examples. I am inheriting from the PocoNet classes as instructed. Right now I can run my server as a service, & receive incoming connections.
如示例所示,我有一个 ServerApplication->TCPServer->ServerSocket + TCPServerConnectionFactory->TCPServerconnection 方法。我按照指示从 PocoNet 类继承。现在我可以将我的服务器作为服务运行,并接收传入的连接。
I want to take an event handling approach to the following: on a per-connection (or per client) basis, handle events such as data available to read on the client socket, error occurred on the client socket (disconnected or timeout), send data without error on client socket.
我想采用以下事件处理方法:在每个连接(或每个客户端)的基础上,处理事件,例如可在客户端套接字上读取的数据、客户端套接字上发生的错误(断开连接或超时)、发送客户端套接字上的数据没有错误。
How do I go about doing it? Is Poco/Foundation/Events what I am looking for, or is there some mechanism implemented in Poco::Net?
我该怎么做?Poco/Foundation/Events 是我正在寻找的,还是在 Poco::Net 中实现了某种机制?
I have seen the Poco::Net::NetExpections but they do not appear to be thrown in my TCPServerConnection-derived class when a netcat connection closes.
我已经看到了 Poco::Net::NetExpections,但是当 netcat 连接关闭时,它们似乎没有被抛出到我的 TCPServerConnection 派生类中。
采纳答案by ?lex
What I ended up using is a different approach as TCPServer is a different beast altogether. Following the example posted hereI ended up with a class inheriting from ServerApplication, and a class which becomes essentially the connection handlerby a SocketReactor.
我最终使用的是一种不同的方法,因为 TCPServer 是完全不同的野兽。按照此处发布的示例,我最终得到了一个继承自ServerApplication的类,以及一个本质上通过SocketReactor成为连接处理程序的类。
Deamonizer header:
Deamonizer 标题:
class Daemon : public ServerApplication
{
public:
Daemon();
/// @Brief The main loop of the daemon, everything must take place here
int main();
};
Deamonizer implementation:
Deamonizer 实现:
int Daemon::main()
{
// Server Socket
ServerSocket svs(2222);
// Reactor-Notifier
SocketReactor reactor;
Poco::Timespan timeout(2000000); // 2Sec
reactor.setTimeout(timeout);
// Server-Acceptor
SocketAcceptor<ConnectionHandler> acceptor(svs, reactor);
// Threaded Reactor
Thread thread;
thread.start(reactor);
// Wait for CTRL+C
waitForTerminationRequest();
// Stop Reactor
reactor.stop();
thread.join();
return Application::EXIT_OK;
}
The handler class can be anything as long as it has a conforming Constructor (see Poco::Net documentation for this). In my case the header looks like this:
处理程序类可以是任何东西,只要它有一个符合标准的构造函数(参见 Poco::Net 文档)。在我的情况下,标题如下所示:
class ConnectionHandler
{
public:
/**
* @Brief Constructor of the Connection Handler
* @Note Each object is unique to an accepted connection
* @Param SteamSocket is the socket accepting the connections
* @See SocketAcceptor http://pocoproject.org/docs/Poco.Net.SocketAcceptor.html
* @Param SocketReactor is the reacting engine (threaded) which creates notifications about the socket
*/
ConnectionHandler(StreamSocket &, SocketReactor &);
/**
* @Brief Destructor
*/
~ConnectionHandler();
/**
* @Brief Event Handler when Socket becomes Readable, i.e: there is data waiting to be read
*/
void onSocketReadable(const AutoPtr<ReadableNotification>& pNf);
/**
* @Brief Event Handler when Socket was written, i.e: confirmation of data sent away (not received by client)
*/
void onSocketWritable(const AutoPtr<WritableNotification>& pNf);
/**
* @Brief Event Handler when Socket was shutdown on the remote/peer side
*/
void onSocketShutdown(const AutoPtr<ShutdownNotification>& pNf);
/**
* @Brief Event Handler when Socket throws an error
*/
void onSocketError(const AutoPtr<ErrorNotification>& pNf);
/**
* @Brief Event Handler when Socket times-out
*/
void onSocketTimeout(const AutoPtr<TimeoutNotification>& pNf);
private:
/**
* @Brief Read bytes from the socket, depending on available bytes on socket
*/
void readBytes();
/**
* @Brief Send message to the socket
* @Param std::string is the message (null terminated)
*/
void sendMessage(std::string);
/// Stream Socket
StreamSocket _socket;
/// Socket Reactor-Notifier
SocketReactor& _reactor;
/// Received Data Buffer
std::vector<char *> in_buffer;
};
How you implement the handler is up to you, provided the only thing that you need to do is register the class methods which handle events like so:
您如何实现处理程序取决于您,只要您需要做的唯一一件事就是注册处理事件的类方法,如下所示:
_reactor.addEventHandler(_socket,NObserver<ConnectionHandler, ReadableNotification>(*this, &ConnectionHandler::onSocketReadable));
_reactor.addEventHandler(_socket,NObserver<ConnectionHandler, ShutdownNotification>(*this, &ConnectionHandler::onSocketShutdown));
_reactor.addEventHandler(_socket,NObserver<ConnectionHandler, ErrorNotification>(*this, &ConnectionHandler::onSocketError));
_reactor.addEventHandler(_socket,NObserver<ConnectionHandler, TimeoutNotification>(*this, &ConnectionHandler::onSocketTimeout));
All in all, two classes, a few lines of code, simple and clean. Absolutely starting to love Poco library! :)
总而言之,两个类,几行代码,简单干净。绝对开始喜欢 Poco 图书馆!:)
回答by Cesar Ortiz
Try with this:
试试这个:
#include <iostream>
#include "Poco/Net/TCPServer.h"
#include "Poco/Net/TCPServerParams.h"
#include "Poco/Net/TCPServerConnectionFactory.h"
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/Socket.h"
using namespace std;
class newConnection: public Poco::Net::TCPServerConnection {
public:
newConnection(const Poco::Net::StreamSocket& s) :
Poco::Net::TCPServerConnection(s) {
}
void run() {
cout << "New connection from: " << socket().peerAddress().host().toString() << endl << flush;
bool isOpen = true;
Poco::Timespan timeOut(10,0);
unsigned char incommingBuffer[1000];
while(isOpen){
if (socket().poll(timeOut,Poco::Net::Socket::SELECT_READ) == false){
cout << "TIMEOUT!" << endl << flush;
}
else{
cout << "RX EVENT!!! ---> " << flush;
int nBytes = -1;
try {
nBytes = socket().receiveBytes(incommingBuffer, sizeof(incommingBuffer));
}
catch (Poco::Exception& exc) {
//Handle your network errors.
cerr << "Network error: " << exc.displayText() << endl;
isOpen = false;
}
if (nBytes==0){
cout << "Client closes connection!" << endl << flush;
isOpen = false;
}
else{
cout << "Receiving nBytes: " << nBytes << endl << flush;
}
}
}
cout << "Connection finished!" << endl << flush;
}
};
int main(int argc, char** argv) {
//Create a server socket to listen.
Poco::Net::ServerSocket svs(1234);
//Configure some server params.
Poco::Net::TCPServerParams* pParams = new Poco::Net::TCPServerParams();
pParams->setMaxThreads(4);
pParams->setMaxQueued(4);
pParams->setThreadIdleTime(100);
//Create your server
Poco::Net::TCPServer myServer(new Poco::Net::TCPServerConnectionFactoryImpl<newConnection>(), svs, pParams);
myServer.start();
while(1);
return 0;
}