Poco c ++ Websocket服务器连接由peer重置

时间:2013-11-18 12:15:46

标签: websocket poco-libraries

我正在编写一种聊天服务器应用程序,其中从一个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
    }

}

5 个答案:

答案 0 :(得分:1)

请参阅receiveFrame()documentation

  

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

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

答案 1 :(得分:1)

我不知道这是否是问题的答案,但你所做的实现并不涉及PING帧。目前(截至我的POCO版本:1.7.5)这不是由POCO框架自动完成的。我提出question about that recently。根据RFC(6465),使用ping和pong帧(以及其他)作为保持活动功能。因此,为了使您的连接随时间保持稳定,这可能是正确的。其中大部分都是我自己的猜测,因为我现在正在尝试这个。

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

答案 2 :(得分:0)

我扩展了catch,为“Connection by peer”做了一些异常处理。

catch (Poco::Net::WebSocketException& exc)
{
// Do something
}
catch (Poco::Exception& e)
{
// This is where the "Connection reset by peer" lands
}

答案 3 :(得分:0)

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

我最终自己实现了一个简单的ping功能,其中客户端针对接收到的每个WS Frame发送一个ACK消息。服务器端的一个单独线程尝试读取ACK消息-现在,它将通过查看 flags | | | | | | | | | | | | | | | | | | | | | |-| |,其中的方法),来检测客户端何时断开连接。 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帧时,我就向服务器(JS)发送一个虚拟的“ ACK”消息。

websocket.onmessage = (evt) => {
    _this.receivedData = JSON.parse(evt.data);
    websocket.send("ACK");
};

答案 4 :(得分:0)

这不是关于断开连接的处理,而是关于连接的稳定性。 在 StreamSocket 模式下的 POCO Websocket 服务器和 C# 客户端存在一些问题。有时客户端发送零长度负载的 Pong 消息并发生断开连接,所以我添加了 Ping 和 Pong 处理代码。

int WebSocketImpl::receiveBytes(void* buffer, int length, int)
{
    char mask[4];
    bool useMask;
    _frameFlags = 0;
    for (;;) {
        int payloadLength = receiveHeader(mask, useMask);
        int frameOp = _frameFlags & WebSocket::FRAME_OP_BITMASK;
        if (frameOp == WebSocket::FRAME_OP_PONG || frameOp == 
            WebSocket::FRAME_OP_PING) {
            std::vector<char> tmp(payloadLength);
            if (payloadLength != 0) {
                receivePayload(tmp.data(), payloadLength, mask, useMask);
            }
            if (frameOp == WebSocket::FRAME_OP_PING) {
                sendBytes(tmp.data(), payloadLength, WebSocket::FRAME_OP_PONG);
            }
            continue;
        }
        if (payloadLength <= 0)
            return payloadLength;
        if (payloadLength > length)
            throw WebSocketException(Poco::format("Insufficient buffer for 
                      payload size %d", payloadLength), 
                      WebSocket::WS_ERR_PAYLOAD_TOO_BIG);
        return receivePayload(reinterpret_cast<char*>(buffer), payloadLength, 
                   mask, useMask);
    }
}