Как настроить прослушивание QTcpServer в одиночку на порту с помощью Win7 - PullRequest
0 голосов
/ 04 октября 2018

Я использую QTcpServer, который должен прослушивать один порт.Язык c ++ с Qt 5.9.Приложение должно работать под Win и Linux, используя MingW.Метод listen из QTcpServer использует стандартный параметр для опций сокетов.Для Win10, Linux эти параметры по умолчанию установлены на одно использование порта прослушивания, поэтому прослушивание работает нормально.К сожалению, напротив, Win7 предлагает совместное использование, которое я должен избегать.Я понял, что класс QAbstractSocket позволяет мне создавать сокет с помощью BindFlag :: DontShareAddress.Я могу переслать дескриптор сокета в QTcpServer.Затем метод listen терпит неудачу (не слушает), заявляя: QTcpServer :: listen () вызывается, когда уже слушает.Я проверяю состояние портов с помощью netstat.Пример моего кода ниже:

    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;
    }
}

Спасибо за любую идею, как установить параметры сокета для эксклюзивного использования порта прослушивания.

Martin

1 Ответ

0 голосов
/ 05 октября 2018

В соответствии с комментарием вам, вероятно, потребуется явно вызвать listen в дескрипторе сокета до вызова QTcpServer::setSocketDescriptor.

Следующий код не протестирован, но должен дать вам некоторое представление ...

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";
}

Кроме того, обратите внимание, что вам нужно быть немного более осторожным с обработкой ошибок - просто вызовите qDebug ипродолжение вернется, чтобы укусить вас в какой-то момент.

...