我目前正在尝试修复我编写的与socket select()调用相关的代理服务器中的错误。我正在使用Poco C ++库(使用SocketReactor),问题实际上是在Poco代码中,这可能是一个错误,但我还没有从他们那里得到任何确认。
正在发生的事情是,当连接突然终止套接字时,select()调用立即返回,这是我认为它的意图吗?无论如何,它返回可读文件描述符集中的所有断开连接的套接字,但问题是,当Poco尝试触发onReadable事件处理程序时,抛出异常“Socket未连接”,这是我将代码放入的位置处理它。鉴于异常被静默捕获并且onReadable事件从未被触发,select()调用会立即返回,导致SocketReactor中出现无限循环。
我正在考虑修改Poco代码,以便不是以静默方式捕获异常,而是触发一个名为onDisconnected的新事件或类似的事件,以便可以执行清理。
我的问题是,是否有任何优雅的方法来确定套接字是否已使用select()调用异常关闭?我正在考虑使用异常消息来确定何时发生这种情况,但这对我来说似乎很脏。
答案 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;
}