How set QTcpServer listening alone on port using Win7

785 Views Asked by At

I use a QTcpServer that should listen alone on port. Language is c++ with Qt 5.9. The application must run under Win and Linux using MingW. The listen method from QTcpServer uses standard parameter for socket options. For Win10, Linux these options are set default to single usage of the listening port so listening works fine. Unfortunatly opposite to that Win7 offers shared usage which i must avoid. I figured out that the QAbstractSocket class let me create a socket with the BindFlag::DontShareAddress. I can forward the socketdescriptor to the QTcpServer. Then the method listen fails (isn't listening) by stating: QTcpServer::listen() called when already listening. I check the ports status by using netstat. My code sample is below:

    bool TcpServer::init(QString ipAddress, quint16 port, Command::RoutingProperty clientSocketKind, QString interfaceName)
{
    if (mServerIsInit == true) // only 1 server instance
    {
        return false;   

    mServer = new (std::nothrow) QTcpServer();
    if (mServer == nullptr)
    {
        return false;
    }

    mClientSocketKind = clientSocketKind;
    mInterfaceName = interfaceName;

// tries to set socket properties to a non sharing port
    QTcpSocket tsocket;

   if (!tsocket.bind(QHostAddress(ipAddress), port, QAbstractSocket::BindFlag::DontShareAddress))
    {
        qDebug() << "Socket bind fails";
    }
    else
    {
        qDebug() << "Socket bind success";
    }
    sd = tsocket.socketDescriptor(); // valid socket descriptor

    if (!mServer->setSocketDescriptor(sd))
    {
        qDebug() << "SocketDescriptor fails";
    }

    sd = mServer->socketDescriptor();
    qDebug() << "Socketdescriptor Server " << sd;
//end tries to set socket properties to a non sharing port

    if (mServer->listen(QHostAddress(ipAddress), port)) // fails with message ... is always listening
//  if (mServer->mServer->isListening()) // is not listening tells netstat
    {
        qDebug() << "Server status for listening ok: " << mServer->isListening();
        qDebug() << "Server listen on " << mServer->serverAddress() << ":" << mServer->serverPort();

        connect(mServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
        connect(mServer, SIGNAL(acceptError(QAbstractSocket::SocketError)), this, SLOT(socketErr(QAbstractSocket::SocketError)));

        mServerIsInit = true;
        return true;
    }
    else
    {
        qDebug() << "Server status for listening fail" << mServer->isListening();
        delete mServer;
        mServer = nullptr;
        return false;
    }
}

Thanks for any idea how to set the socket options for a exclusive usage of the listening port.

Martin

1

There are 1 best solutions below

1
On

As per the comment, you will probably need to call listen explicitly on the socket descriptor before calling QTcpServer::setSocketDescriptor.

The following code is untested but should give you some idea...

if (!tsocket.bind(QHostAddress(ipAddress), port, QAbstractSocket::BindFlag::DontShareAddress))
{
    qDebug() << "Socket bind fails";
}
else
{
    qDebug() << "Socket bind success";
}
sd = tsocket.socketDescriptor(); // valid socket descriptor

/*
 * Now make an explicit call to `listen' so that the socket descriptor
 * can be passed to QTcpSocket::setSocketDescriptoy.
 */
if (listen(sd, SOMAXCONN) == SOCKET_ERROR)
{
  printf("Listen failed with error: %ld\n", WSAGetLastError());
  closesocket(sd);
  WSACleanup();

  /*
   * Handle error.
   */
}

if (!mServer->setSocketDescriptor(sd))
{
    qDebug() << "SocketDescriptor fails";
}

As an aside, note that you need to be a bit more careful with error handling -- simply call qDebug and continuing will come back to bite you at some point.