在 Poco Framework 中在一个线程中处理 websocket
Process websocket in one thread in Poco Framework
我正在尝试结合使用 Poco::Net::Websocket 和 Poco::Net::SocketReactor。
使用 Poco::Net;
class WSConnection: public HTTPRequestHandler{
public:
WSConnection(SocketReactor& reactor):_reactor(reactor){};
void handleRequest(HTTPServerRequest& rqst, HTTPServerResponse& rpns){
this->_ws = new Websocket(rqst, rspns);
this->_reactor.addHandler(this._ws, this._onread_hnd);
this->_reactor.addHandler(this._ws, this._onwrite_hnd);
this->_reactor.addHandler(this._ws, this._onerror_hnd);
}
private:
SocketReactor& _reactor;
};
class WSFactory : public HTTPRequestHandlerFactory{
public:
WSFactory(SocketRactor& reactor): _reactor(reactor){};
void HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request)
{
if (!IsWSRequest(request)){
return 0;
}
return new WSConnection(this->_reactor);
}
private:
bool IsWSRequest(const HTTPServerRequest& request){...}
SocketReactor& _reactor;
}
int WSServerApp::main(...){
Poco::Net::SocketReactor r;
Poco::Thread thrd;
WSFactory fctry(r);
Poco::Net::HTTPServer serv(fctry, 35035);
serv.start();
thrd.start(r);
waitForTerminationRequest();
r.stop();
thrd.join();
serv.stop();
}
但是如果我的代码离开 handleRequest(),我会调用析构函数 WSConnection();
还有其他方法可以在一个线程中处理连接吗?
我找到了解决方案。需要写两个类:
Server(ServerSocket 上的包装器)用部分副本重写 运行 方法 Poco::Net::TCPServer:: 运行().
Server::Server(const Poco::UInt16 port, const std::string& serv_name):
Runnable(),
SERVER_NAME(serv_name),
_stop(true),
_sock(port),
_clients(),
_thrd(),
_param(new HTTPServerParams())
{
_thrd.setPriority(Poco::Thread::PRIO_HIGH);
_thrd.setName(SERVER_NAME);
_param->setSoftwareVersion(SERVER_NAME);
}
void Server::run(){
while(!_stop.load()){
Poco::Timespan tm(250000);
if (_sock.poll(tm, Socket::SELECT_READ)){
auto ss = _sock.acceptConnection();
ss.setNoDelay(true);
#if defined(POCO_OS_FAMILY_UNIX)
if (ss.address().family() == AddressFamily::UNIX_LOCAL)
{
//ONLY WEBSOCK
throw Poco::IllegalStateException();
}
#endif
auto conn = std::make_shared<Connection>(ss, _param);
_clients.push_back(conn); //std::vector<std::shared_ptr<Websocket>>
}
}
}
and Connection with partial copy Poco::Net::HTTPServerConnection::运行()
Connection::Connection(StreamSocket& ss, HTTPServerParams::Ptr param):
HTTPServerSession(ss, param),
_ws(), //std::unique_ptr<Websocket>
_rqst(), //std::unique_ptr<HTTPServerRequestImpl>
_rspns() //std::unique_ptr<HTTPServerResponseImpl>
{
_rspns.reset(new HTTPServerResponseImpl(*this));
_rqst.reset(new HTTPServerRequestImpl(*_rspns, *this, param));
//may bee need try and cath with send error state
Init(param);
_ws.reset(new WebSocket(*_rqst, *_rspns));
}
void Connection::Init(const HTTPServerParams::Ptr& param){
_rspns->setDate(Poco::Timestamp());
_rspns->setVersion(_rqst->getVersion());
_rspns->set("Server", param->getSoftwareVersion());
_rspns->setKeepAlive(param->getKeepAlive() && _rqst->getKeepAlive());
}
并添加 SocketReactor 或 Socket::select 调用另一个线程。
我正在尝试结合使用 Poco::Net::Websocket 和 Poco::Net::SocketReactor。 使用 Poco::Net;
class WSConnection: public HTTPRequestHandler{
public:
WSConnection(SocketReactor& reactor):_reactor(reactor){};
void handleRequest(HTTPServerRequest& rqst, HTTPServerResponse& rpns){
this->_ws = new Websocket(rqst, rspns);
this->_reactor.addHandler(this._ws, this._onread_hnd);
this->_reactor.addHandler(this._ws, this._onwrite_hnd);
this->_reactor.addHandler(this._ws, this._onerror_hnd);
}
private:
SocketReactor& _reactor;
};
class WSFactory : public HTTPRequestHandlerFactory{
public:
WSFactory(SocketRactor& reactor): _reactor(reactor){};
void HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request)
{
if (!IsWSRequest(request)){
return 0;
}
return new WSConnection(this->_reactor);
}
private:
bool IsWSRequest(const HTTPServerRequest& request){...}
SocketReactor& _reactor;
}
int WSServerApp::main(...){
Poco::Net::SocketReactor r;
Poco::Thread thrd;
WSFactory fctry(r);
Poco::Net::HTTPServer serv(fctry, 35035);
serv.start();
thrd.start(r);
waitForTerminationRequest();
r.stop();
thrd.join();
serv.stop();
}
但是如果我的代码离开 handleRequest(),我会调用析构函数 WSConnection(); 还有其他方法可以在一个线程中处理连接吗?
我找到了解决方案。需要写两个类:
Server(ServerSocket 上的包装器)用部分副本重写 运行 方法 Poco::Net::TCPServer:: 运行().
Server::Server(const Poco::UInt16 port, const std::string& serv_name):
Runnable(),
SERVER_NAME(serv_name),
_stop(true),
_sock(port),
_clients(),
_thrd(),
_param(new HTTPServerParams())
{
_thrd.setPriority(Poco::Thread::PRIO_HIGH);
_thrd.setName(SERVER_NAME);
_param->setSoftwareVersion(SERVER_NAME);
}
void Server::run(){
while(!_stop.load()){
Poco::Timespan tm(250000);
if (_sock.poll(tm, Socket::SELECT_READ)){
auto ss = _sock.acceptConnection();
ss.setNoDelay(true);
#if defined(POCO_OS_FAMILY_UNIX)
if (ss.address().family() == AddressFamily::UNIX_LOCAL)
{
//ONLY WEBSOCK
throw Poco::IllegalStateException();
}
#endif
auto conn = std::make_shared<Connection>(ss, _param);
_clients.push_back(conn); //std::vector<std::shared_ptr<Websocket>>
}
}
}
and Connection with partial copy Poco::Net::HTTPServerConnection::运行()
Connection::Connection(StreamSocket& ss, HTTPServerParams::Ptr param):
HTTPServerSession(ss, param),
_ws(), //std::unique_ptr<Websocket>
_rqst(), //std::unique_ptr<HTTPServerRequestImpl>
_rspns() //std::unique_ptr<HTTPServerResponseImpl>
{
_rspns.reset(new HTTPServerResponseImpl(*this));
_rqst.reset(new HTTPServerRequestImpl(*_rspns, *this, param));
//may bee need try and cath with send error state
Init(param);
_ws.reset(new WebSocket(*_rqst, *_rspns));
}
void Connection::Init(const HTTPServerParams::Ptr& param){
_rspns->setDate(Poco::Timestamp());
_rspns->setVersion(_rqst->getVersion());
_rspns->set("Server", param->getSoftwareVersion());
_rspns->setKeepAlive(param->getKeepAlive() && _rqst->getKeepAlive());
}
并添加 SocketReactor 或 Socket::select 调用另一个线程。