QTcpSocket -退出QRunnable时指定的句柄无效

QTcpSocket - An invalid handle was specified when exting QRunnable

本文关键字:句柄 无效 退出 QRunnable QTcpSocket      更新时间:2023-10-16

这个错误发生在代码段:

void TCPConnectThread::run()
{
    m_socket = new QTcpSocket();
    m_socket->setSocketDescriptor(m_fd);
    m_socket->waitForReadyRead(10000);
    QString data = m_socket->readAll();
    m_socket->waitForDisconnected();
}

if (::WSAIoctl(socketDescriptor, FIONREAD, &dummy, sizeof(dummy), &nbytes,  
sizeof(nbytes), &sizeWritten, 0,0) == SOCKET_ERROR) <-Exception here
{
    WS_ERROR_DEBUG(WSAGetLastError());
    return -1;
}

更深层次:

if (::getsockopt(d->socketDescriptor, SOL_SOCKET, 
SO_ERROR, (char *) &value, &valueSize) == 0) <-Here

退出run方法时发生invalid handle异常。

下面是获取m_socket的方法:
m_socket = new QTcpSocket();
m_socket->setSocketDescriptor(m_fd);//m_fd is the socket descriptor of another socket
                                    //from another thread

下面是收集m_fd的线程:

void TCPListenerThread::onNewConnection()
{
    QTcpSocket *clientSocket = m_tcpServer->nextPendingConnection();
    int sockfd = clientSocket->socketDescriptor();
    m_connectThread = new TCPConnectThread(sockfd);
    m_threadPool->start(m_connectThread);
}
异常:

Most possible exception at 0x76edf9ea in manager_host.exe:   
0xC0000008: An invalid handle was specified  

如何以及在哪里可以找到这个无效句柄

不能使用QTcpSocket对象的套接字描述符,如果它已经被另一个QTcpSocket对象使用。一旦分配给QTcpSocket

,也没有办法取消分配。

即使你没有显式地使用初始的QTcpSocket,如果在它被创建的线程中有一个事件循环(这可能是这里的情况),Qt将在该线程中监视它。

作为另一种选择,您可以:

  • 派生QTcpServer类来重新定义它的incomingConnection(int socketDescriptor)方法,以便在它被分配给QTcpSocket之前获得描述符,而不是使用nextPendingConnection
  • 直接将从nextPendingConnection接收到的QTcpSocket而不是套接字描述符作为参数传递给线程构造器,并将其移动到另一个线程(参见注释):

    TCPConnectThread(QTcpSocket *socket)
        : m_socket(socket) 
    {
        m_socket−>setParent(0); // necessary to move the object to another thread
        m_socket->moveToThread(this);
        ...
    }
    

    由于移动必须从初始线程完成,第一个备选方案可能更容易使用QRunnable,因为您可能无法轻松访问可运行程序将使用的未来QThread