2

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

发生的情况是,每当连接突然终止时,套接字 select() 调用就会立即返回,这就是我认为它应该做的事情?无论如何,它会返回可读文件描述符集中的所有断开连接的套接字,但问题是当 Poco 尝试触发 onReadable 事件处理程序时抛出异常“套接字未连接”,这是我将放置代码的地方处理它。鉴于异常被静默捕获并且永远不会触发 onReadable 事件,因此 select() 调用会立即返回,从而导致 SocketReactor 中的无限循环。

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

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

4

3 回答 3

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;
}
于 2012-01-01T11:51:12.793 回答
1

只需抓住ConnectionResetExceptionin OnReadable()(处理ReadableNotification)然后它会正确处理“对等方重置连接”。

catch(Poco::Net::ConnectionResetException &ex)
{
    _socket.shutdownSend();
    delete this;
}
于 2012-09-16T15:00:29.907 回答
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 相同的错误被抛出。

于 2010-05-03T07:17:24.930 回答