QTcpServer nextPendingConnection returns socket with wrong port in Thread



  • Hello,

    i have the problem that multiple threads are supposed to share one established tcp connection to send messages.
    Thefore I have a server-like app which waits for incoming connections. In order to share the connection i have a class NetworkManager which has TcpWorker* child and a QThread* TcpThread.
    When constructing the NetworkManager a new TcpWorker and a new QThread are created and
    @
    TcpWorker.moveToThread(TcpThread);
    connect(this, SIGNAL(waitForTcp(int port)), TcpWorker, SLOT(waitForTcp(int)));
    TcpThread.start();
    @

    Inside the TcpWorker i have a variable QTcpServer* m_srv and the slots
    @

    void TcpWorker::waitForTcp(int port) {
    m_tcpServer = new QTcpServer();
    connect(m_srv, SIGNAL(newConnection()), this, SLOT(on_serverConnection()));
    std::cerr << " listening on port " << port << std::endl;
    if ( !m_tcpServer->listen(QHostAddress::Any, port) ) {
    std::cerr << "unable to listen on port" << port << std::endl;
    }
    }

    void TcpWorker::on_serverConnection() {
    if ( !m_tcpSocket ) {
    m_tcpSocket = m_srv->nextPendingConnection();
    connect(m_tcpSocket, SIGNAL(connected()), this, SLOT(on_tcpConnected()));
    connect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(on_tcpDisconnected()));
    std::cout << "tcpsock: " << m_tcpSocket << " connection established " << qPrintable(m_tcpSocket->peerAddress().toString()) << " and port " << m_tcpSocket->peerPort() << std::endl;
    m_isConnected = true;
    emit tcpConnected();
    }
    }
    @

    and then somewhere i emit waitForTcp(12997)
    The slots is successully executed, and when trying to connect to the application on_serverConnection is executed, but peerPort of m_tcpSocket returns an arbitrary port between 40000 and 70000.

    What is wrong in my scenario?

    Thank you for your help!

    Kind regards



  • that's proper and expected behaviour for established TCP sockets.
    an established socket pair is uniquely characterized by four numbers:

    • (listen ip address, listen tcp port)
    • (active ip address, active tcp port)

    the active tcp port is also called ephemeral because it's temporarily and randomly allocated by the OS and used to uniquely identify the one end of the connection (the active one, i.e. the one that initiates the connection).

    this, for example, easily avoids problems of identifying different established sockets for multiple connections (probably across different applications) from a machine to a service that it hosts.



  • This is what I have understood from your explanation.

    1. Client
    2. Server
    3. Server has multiple threads
    4. Client Connects to Server
    5. Multiple threads need to share the same established connection to send messages.
      It is as good server turning out to be client and client turning out to be as server once connection establishment happens.

    Hope this is correct problem statement.

    1. Generally servers are assigned with fixed port
    2. Clients are not assigned with fixed port. If you want the fixed port for client also you can assign the fixed for client end point. If you don't assign the fixed port, TCP will randomly assign the port to client end point.
    3. Once the connection establishes between client and server, socket end point has to be shared between multiple threads in server.

    Hope this clarifies the overall scenario for you. If you have different issue I can help you. Do let me know.



  • Thank you two for your responses.
    Okay, this makes sense, I just was wondering why the sent data is never received and thought it was caused by a faulty TCP socket.

    But now im not sure why my data is never received:
    The application which initiates the connection establishment also has an instance of NetworkManager (and thus a TcpWorker object running in a Thread).
    The connection establishment works fine, the responder application recognizes an incoming connection and sends a message. But it is (not always) received by the initiating app.
    The connected signal is emitted by m_tcpSocket and processed by
    @
    void TcpWorker::on_tcpConnected() {
    std::cerr << "TcpWorkerontcpConnected is in thread " << QThread::currentThreadId() << std::endl;
    m_isConnected = true;
    connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(on_readyRead()));
    connect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(on_tcpDisconnected()));
    emit tcpConnected();
    }
    @

    But the readyRead is not executed. Might this be problem caused by my testing on localhost? Further, if I print the peerPort of the m_tcpSocket in this slot it is 12997. But I think this is correct?

    Would be nice if anyone has an idea.

    Regards

    i modified the on_tcpConnected by adding
    @
    m_tcpSocket->waitForReadyRead(5000);
    std::cerr << "available: " << m_tcpSocket.bytesAvailable() << std::endl;
    @
    No data is arriving on the socket. But i have no idea why. The sending application says that bytes were successfully written to the socket.

    Also when i close the socket from one side via disconnectFromHost the other side does not emit the disconnected signal. Something is basically wrong, but what? Isn't it possible to move a tcp communication into thread like that?

    Edit: Finally found a problem. I connectec the same signal to send a TCP message (inside Networkmanager) twice to the same slot in TcpWorker.
    Now the packet is received at the other side.



  • You can put the question in to SOLVED state by editing the question. This will close the issue.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.