套接字select()处理突然断开连接

时间:2010-04-30 06:32:03

标签: c++ sockets select poco-libraries

我目前正在尝试修复我编写的与socket select()调用相关的代理服务器中的错误。我正在使用Poco C ++库(使用SocketReactor),问题实际上是在Poco代码中,这可能是一个错误,但我还没有从他们那里得到任何确认。

正在发生的事情是,当连接突然终止套接字时,select()调用立即返回,这是我认为它的意图吗?无论如何,它返回可读文件描述符集中的所有断开连接的套接字,但问题是,当Poco尝试触发onReadable事件处理程序时,抛出异常“Socket未连接”,这是我将代码放入的位置处理它。鉴于异常被静默捕获并且onReadable事件从未被触发,select()调用会立即返回,导致SocketReactor中出现无限循环。

我正在考虑修改Poco代码,以便不是以静默方式捕获异常,而是触发一个名为onDisconnected的新事件或类似的事件,以便可以执行清理。

我的问题是,是否有任何优雅的方法来确定套接字是否已使用select()调用异常关闭?我正在考虑使用异常消息来确定何时发生这种情况,但这对我来说似乎很脏。

3 个答案:

答案 0 :(得分:2)

我有同样的问题。解决它的唯一方法是控制客户端应用程序退出代码。我使用的解决方案是在客户端终止反应器之前发送关闭信号。然后在服务器上,您只需关闭套接字。

//Client:
//Handler Class: onWrite
Packet p = Packet::Shutdown();

if (p.fn == "shutdown")
{
    _reactor.stop();
    delete this;
}

//Server
//Accepter Class: onRead
if (p.fn == "shutdown")
{
    printf("%s has disconnected", _username.c_str());
    _socket.close();
    delete this;
}

答案 1 :(得分:1)

看来你是对的雷米。我设法使用以下代码区分套接字是否已断开连接(这已添加到Poco / Net / src / SocketImpl.cpp):

bool SocketImpl::isConnected()
{
int bytestoread;
int rc;
fd_set fdRead;

FD_ZERO(&fdRead);
FD_SET(_sockfd, &fdRead);

struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 250000;

rc = ::select(int(_sockfd) + 1, &fdRead, (fd_set*) 0, (fd_set*) 0, &tv);
ioctl(FIONREAD, &bytestoread);

return !((bytestoread == 0) && (rc == 1));
}

根据我的理解,这将检查套接字是否可以通过调用select()来读取,然后检查该套接字上可用的实际字节数。如果套接字报告它是可读的但是字节为0则则套接字实际上没有连接。

虽然这回答了我的问题,但遗憾的是这还没有解决我的Poco问题,因为我无法找到解决Poco SocketReactor代码的方法。我尝试创建一个名为DisconnectNotification的新事件,但遗憾的是无法调用它,因为与关闭套接字上的ReadNotification一样,会抛出相同的错误。

答案 2 :(得分:1)

抓住ConnectionResetException中的OnReadable()(处理ReadableNotification) 然后它正确地处理“由同伴重置连接”。

catch(Poco::Net::ConnectionResetException &ex)
{
    _socket.shutdownSend();
    delete this;
}