Poco c++;对等方重置Websocket服务器连接

Poco c++;对等方重置Websocket服务器连接,websocket,poco-libraries,Websocket,Poco Libraries,我正在编写一种聊天服务器应用程序,其中从一个websocket客户端接收的消息被发送到所有其他websocket客户端。为此,我将连接的客户端保存在一个列表中。当客户端断开连接时,我需要将其从列表中删除(以便将来的“发送”不会失败) 但是,有时当客户端断开连接时,服务器只会收到一个异常“由对等方重置连接”,并且代码没有机会从客户端列表中删除。有没有一种方法可以保证“很好”地通知连接已重置 我的代码是: void WsRequestHandler::handleRequest(HTTPServer

我正在编写一种聊天服务器应用程序,其中从一个websocket客户端接收的消息被发送到所有其他websocket客户端。为此,我将连接的客户端保存在一个列表中。当客户端断开连接时,我需要将其从列表中删除(以便将来的“发送”不会失败)

但是,有时当客户端断开连接时,服务器只会收到一个异常“由对等方重置连接”,并且代码没有机会从客户端列表中删除。有没有一种方法可以保证“很好”地通知连接已重置

我的代码是:

void WsRequestHandler::handleRequest(HTTPServerRequest &req, HTTPServerResponse &resp)
{
    int             n;
    Poco::Timespan  timeOut(5,0);

    try
    {
        req.set("Connection","Upgrade"); // knock out any extra tokens firefox may send such as "keep-alive"
        ws = new WebSocket(req, resp);
        ws->setKeepAlive(false);
        connectedSockets->push_back(this);

        do
        {
            flags = 0;
            if (!ws->poll(timeOut,Poco::Net::Socket::SELECT_READ || Poco::Net::Socket::SELECT_ERROR))
            {
//                  cout << ".";
            }
            else
            {
                n = ws->receiveFrame(buffer, sizeof(buffer), flags);
                if (n > 0)
                {
                    if ((flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_BINARY)
                    {
                        // process and send out to all other clients
                        DoReceived(ws, buffer, n);
                    }
                }
            }
        }
        while ((flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE);
        // client has closed, so remove from list
        for (vector<WsRequestHandler *>::iterator it = connectedSockets->begin() ; it != connectedSockets->end(); ++it)
        {
            if (*it == this)
            {
                connectedSockets->erase(it);
                logger->information("Connection closed %s", ws->peerAddress().toString());
                break;
            }
        }
        delete(ws);
        ws = NULL;
    }
    catch (WebSocketException& exc)
    {
    //never gets called
    }

}
void WsRequestHandler::handleRequest(HTTPServerRequest&req、HTTPServerResponse&resp)
{
int n;
Poco::Timespan超时(5,0);
尝试
{
req.set(“连接”、“升级”);//删除firefox可能发送的任何额外标记,如“保持活动”
ws=新的WebSocket(请求、响应);
ws->setKeepAlive(false);
连接的插座->推回(此);
做
{
flags=0;
如果(!ws->poll(超时,Poco::Net::Socket::SELECT_READ | | Poco::Net::Socket::SELECT_ERROR))
{
//cout receiveFrame(缓冲区、sizeof(缓冲区)、标志);
如果(n>0)
{
if((标志和WebSocket::FRAME\u OP\u位掩码)==WebSocket::FRAME\u OP\u二进制)
{
//处理并发送给所有其他客户
数据接收(ws,buffer,n);
}
}
}
}
while((flags&WebSocket::FRAME\u OP\u BITMASK)!=WebSocket::FRAME\u OP\u CLOSE);
//客户端已关闭,请从列表中删除
对于(向量::迭代器it=connectedSockets->begin();it!=connectedSockets->end();++it)
{
如果(*it==此)
{
已连接套接字->擦除(it);
日志程序->信息(“连接已关闭%s”,ws->peerAddress().toString());
打破
}
}
删除(ws);
ws=NULL;
}
捕获(WebSocketException和exc)
{
//从未接到过电话
}
}

我扩展了捕获,为“对等连接重置”做了一些异常处理


我扩展了catch,为“对等连接重置”做了一些异常处理

请参见receiveFrame():

返回接收到的字节数。返回值0表示对等方已关闭或关闭连接

所以,如果receiveFrame()调用返回零,则可以执行相应的操作。

请参阅receiveFrame():

返回接收到的字节数。返回值0表示对等方已关闭或关闭连接


因此,如果receiveFrame()调用返回零,您可以采取相应的行动。

我不知道这是否是问题的答案,但您所做的实现没有处理PING帧。目前(从我的POCO版本1.7.5开始),POCO框架并没有自动完成这项工作。我贴了一张照片。根据RFC(6465),乒乓和乒乓帧(除其他外)用作保持活动功能。因此,为了使您的连接随着时间的推移保持稳定,这可能是正确操作的关键。这大部分是我自己的猜测工作,因为我现在自己也在尝试


@Alex,我相信您是POCO的主要开发人员,如果您能对我的答案发表评论,我将不胜感激。

我不知道这是否是问题的答案,但您所做的实现并不涉及PING帧。目前(从我的POCO版本1.7.5开始),POCO框架并没有自动完成这项工作。我贴了一张照片。根据RFC(6465),乒乓和乒乓帧(除其他外)用作保持活动功能。因此,为了使您的连接随着时间的推移保持稳定,这可能是正确操作的关键。这大部分是我自己的猜测工作,因为我现在自己也在尝试


@Alex,你是POCO的主要开发者,我相信,如果你能对我的答案发表评论,我将不胜感激。

来这里参加聚会有点晚了。。。但我也在使用Poco和Websockets——正确处理断开连接是很棘手的

最后,我自己实现了一个简单的ping功能,客户端为接收到的每个WS-Frame发送一个ACK消息。服务器端的一个单独线程尝试读取ACK消息,现在它将通过查看标志| WebSocket::FRAME_OP_CLOSE来检测客户端何时断开连接

//Serverside - POCO. Start thread for receiving ACK packages. Needed in order to detect when websocket is closed!
thread t0([&]()->void{
    while((!KillFlag && ws!= nullptr && flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE && machineConnection != nullptr){
        try{
            if(ws == nullptr){
                return;
            }
            if(ws->available() > 0){
                int len = ws->receiveFrame(buffer, sizeof(buffer), flags);
            }
            else{
                Util::Sleep(10);
            }
        }
        catch(Poco::Exception &pex){
            flags = flags | WebSocket::FRAME_OP_CLOSE;
            return;
        }
        catch(...){
            //log::info(string("Unknown exception in ACK Thread drained"));
            return;
        }
    }
    log::debug("OperatorWebHandler::HttpRequestHandler() Websocket Acking thread DONE");
});
在客户端,每次从服务器(POCO)收到WS-frame时,我都会向服务器(JS)发送一个虚拟的“ACK”消息


来这里参加聚会有点晚了。。。但我也在使用Poco和Websockets——正确处理断开连接是很棘手的

最后,我自己实现了一个简单的ping功能,客户端为接收到的每个WS-Frame发送一个ACK消息。服务器端的一个单独线程尝试读取ACK消息,现在它将通过查看标志| WebSocket::FRAME_OP_CLOSE来检测客户端何时断开连接

//Serverside - POCO. Start thread for receiving ACK packages. Needed in order to detect when websocket is closed!
thread t0([&]()->void{
    while((!KillFlag && ws!= nullptr && flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE && machineConnection != nullptr){
        try{
            if(ws == nullptr){
                return;
            }
            if(ws->available() > 0){
                int len = ws->receiveFrame(buffer, sizeof(buffer), flags);
            }
            else{
                Util::Sleep(10);
            }
        }
        catch(Poco::Exception &pex){
            flags = flags | WebSocket::FRAME_OP_CLOSE;
            return;
        }
        catch(...){
            //log::info(string("Unknown exception in ACK Thread drained"));
            return;
        }
    }
    log::debug("OperatorWebHandler::HttpRequestHandler() Websocket Acking thread DONE");
});
在客户端,每次从服务器(POCO)收到WS-frame时,我都会向服务器(JS)发送一个虚拟的“ACK”消息


你有没有找到解决问题的办法?当客户端断开连接时,我也会得到“由对等方重置连接”。你有没有找到解决问题的方法?当客户端断开连接时,我还会收到“由对等方重置连接”的消息。报告了有关此问题的问题:报告了有关此问题的问题:
websocket.onmessage = (evt) => {
    _this.receivedData = JSON.parse(evt.data);
    websocket.send("ACK");
};