Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QTcpServer and listening on multiple ports

QTcpServer and listening on multiple ports

Scheduled Pinned Locked Moved Solved General and Desktop
11 Posts 4 Posters 3.7k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    steveq
    wrote on last edited by
    #1

    Hey All,

    I suspect I haven't quite grasped how QTcpServer works.

    I'm writing a (not so) simple network chat program. I've realised that to chat to more than one client on the same WAN address, I need to use multiple ports (with NAT rules on the router).

    QTcpServer::listen only allows you to listen to the one port. Is there a way to listen on a port range (ie: 7770:7800)?

    Am I approaching this the wrong way perhaps?

    It seems like a simple enough solution, but it currently eludes me.

    Thanks in advance for your help.

    Steve Q. :-)

    aha_1980A 1 Reply Last reply
    0
    • Kent-DorfmanK Offline
      Kent-DorfmanK Offline
      Kent-Dorfman
      wrote on last edited by
      #2

      @steveq said in QTcpServer and listening on multiple ports:

      QTcpServer::listen only allows you to listen to the one port. Is there a way to listen on a port range (ie: 7770:7800)?

      No. TCP is session oriented, so it is essentially point-to-point. You can connect multiple clients to a single TCP port, and the server must differentiate between the individual sessions. In the POSIX world this was historically done by forking the server process so that each session had its own server process running. Aggregating multiple sessions under a single server process is more complicated.

      Am I approaching this the wrong way perhaps?

      I doubt your clients are all under the same WAN address. More likely your server is sitting behind NAT so it has a single hidden address but presents a single public IP to the WAN. For the clients to get thru to the NATTed server your router must do port forwarding when an external client wishes to make a connection.

      Even if your clients themselves are NATTed on the other end, the routers should handle remapping to the correct IP if you are using TCP.

      1 Reply Last reply
      4
      • S steveq

        Hey All,

        I suspect I haven't quite grasped how QTcpServer works.

        I'm writing a (not so) simple network chat program. I've realised that to chat to more than one client on the same WAN address, I need to use multiple ports (with NAT rules on the router).

        QTcpServer::listen only allows you to listen to the one port. Is there a way to listen on a port range (ie: 7770:7800)?

        Am I approaching this the wrong way perhaps?

        It seems like a simple enough solution, but it currently eludes me.

        Thanks in advance for your help.

        Steve Q. :-)

        aha_1980A Offline
        aha_1980A Offline
        aha_1980
        Lifetime Qt Champion
        wrote on last edited by aha_1980
        #3

        @steveq

        just to add to @Kent-Dorfman, you are looking for https://doc.qt.io/qt-5/qtcpserver.html#newConnection and https://doc.qt.io/qt-5/qtcpserver.html#nextPendingConnection

        No need for multiple ports, threads or forking.

        Regards

        Edit: https://wiki.qt.io/WIP-How_to_create_a_simple_chat_application might be interesting for you, too.

        Qt has to stay free or it will die.

        1 Reply Last reply
        2
        • S Offline
          S Offline
          steveq
          wrote on last edited by
          #4

          Hey @Kent-Dorfman and @aha_1980,
          Thanks so much for your prompt replies!

          So I still think I'm not getting this.

          The scenario I was talking about is this:
          Let's say I have a static IP address of 1.2.3.4 and I am using port 7770 to chat on. The router connected to that IP address has a NAT rule in it port forwarding 1.2.3.4:7770 to 192.168.1.2:7770. Now lets say I have a second machine on the same IP 1.2.3.4 and it has a LAN IP address of 192.168.1.3. We also want to chat to this machine. I can''t see how to do it unless I use another port so the router would have a rule 1.2.3.4:7771 to 192.168.1.3:7771.

          Does this make sense? My TCP listener would have to monitor both ports (although obviously not as I am not getting it!!).

          @aha_1980 I use newConnection and nextPendingConnection already. In fact my software is running really well when talking to machine, I just can't get my head around how to connect to to different machines behind the same static IP.

          Here is where I set up my server:

          	// Listen for any chat requests
          	m_pChatTcpServer = new QTcpServer(this);
          
          	connect(m_pChatTcpServer, SIGNAL(newConnection()), this, SLOT(chatNewConnection()));
          	connect(m_pChatTcpServer, SIGNAL(acceptError(QAbstractSocket::SocketError)), this, SLOT(chatServerError(QAbstractSocket::SocketError)));
          
          	m_pChatTcpServer->listen(QHostAddress::Any, static_cast<quint16>(m_settings.chatPort));
          

          And where I get a newConnection:

          // Called when a new chat connection comes in without us asking for it (m_pChatTcpServer)
          void MainWindow::chatNewConnection()
          {
          	 SQTcpSocket *socket = static_cast<SQTcpSocket *>(m_pChatTcpServer->nextPendingConnection());
          
          	 // Temporarily connect these signals until I am ready to hand this socket off to my ClientServer object
          	 connect(socket, SIGNAL(readyRead()), this, SLOT(chatReadyRead()),Qt::UniqueConnection);
          	 connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(chatConnectionError(QAbstractSocket::SocketError)),Qt::UniqueConnection);
          	 connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(chatTcpSocketState(QAbstractSocket::SocketState)),Qt::UniqueConnection);
          	 connect(socket, SIGNAL(disconnected()), this, SLOT(chatOnConnectionTerminated()),Qt::ConnectionType(Qt::UniqueConnection));
          	 connect(socket, SIGNAL(connected()), this, SLOT(chatOnConnectionEstablished()),Qt::UniqueConnection);
          }
          

          And then receiving the message form the server

          // Here for convenience in case I ever need it. Does nothing because any ready will be done once the socket is handed off to my ClientServer class
          void MainWindow::chatReadyRead()
          {
          	SQTcpSocket *socket = static_cast<SQTcpSocket *>(sender());
          
          	while(socket->bytesAvailable())
          	{
          		QByteArray receivedData = socket->readAll();
          
          		QDataStream ds1(receivedData.mid(0, 4));
          
          		ds1.setByteOrder(QDataStream::LittleEndian);
          
          		int messageSize;
          		ds1 >> messageSize;
          
          		QDataStream ds2(receivedData.mid(4, 4));
          
          		ds2.setByteOrder(QDataStream::LittleEndian);
          
          		int messageType;
          		ds2 >> messageType;
          
          		switch( messageType)
          		{
          			// Initial hand shaking message
          			case CHATMESSAGE_HELLO:
          			{
          				QString uuid, nameColour, nickName;
          
          				uuid = receivedData.mid(8, 32);
          
          				nameColour = receivedData.mid(40, 7);
          				nickName = receivedData.mid(47, -1);
          
          				// Reply back with my initial HELLO (using the same uuid so we both appear in the correct chat tab) message with the nick name colour and nick name
          				unsigned int messageType = CHATMESSAGE_HELLO;
          
          				QByteArray l_vDataToBeSent;
          
          				QDataStream l_vStream(&l_vDataToBeSent, QIODevice::WriteOnly);
          
          				l_vStream.setByteOrder(QDataStream::LittleEndian);
          
          				unsigned int size = sizeof(messageType) + static_cast<unsigned int>(m_settings.nickNameColour.length()) + static_cast<unsigned int>(m_settings.nickName.length()) + static_cast<unsigned int>(uuid.length());
          
          				l_vStream << size;
          
          				l_vStream << messageType;
          
          				l_vDataToBeSent.append(uuid);
          				l_vDataToBeSent.append(m_settings.nickNameColour);
          				l_vDataToBeSent.append(m_settings.nickName);
          
          				if ( socket ) socket->write(l_vDataToBeSent, l_vDataToBeSent.length());
          
          				// Now start the new chat
          				startNewChat( socket, uuid, nameColour, nickName );
          
          				break;
          			}
          		}
          	}
          }
          

          Thanks in advance guys, I think I am totally missing how this works here.

          Regards,

          Steve Q.

          aha_1980A 1 Reply Last reply
          0
          • S steveq

            Hey @Kent-Dorfman and @aha_1980,
            Thanks so much for your prompt replies!

            So I still think I'm not getting this.

            The scenario I was talking about is this:
            Let's say I have a static IP address of 1.2.3.4 and I am using port 7770 to chat on. The router connected to that IP address has a NAT rule in it port forwarding 1.2.3.4:7770 to 192.168.1.2:7770. Now lets say I have a second machine on the same IP 1.2.3.4 and it has a LAN IP address of 192.168.1.3. We also want to chat to this machine. I can''t see how to do it unless I use another port so the router would have a rule 1.2.3.4:7771 to 192.168.1.3:7771.

            Does this make sense? My TCP listener would have to monitor both ports (although obviously not as I am not getting it!!).

            @aha_1980 I use newConnection and nextPendingConnection already. In fact my software is running really well when talking to machine, I just can't get my head around how to connect to to different machines behind the same static IP.

            Here is where I set up my server:

            	// Listen for any chat requests
            	m_pChatTcpServer = new QTcpServer(this);
            
            	connect(m_pChatTcpServer, SIGNAL(newConnection()), this, SLOT(chatNewConnection()));
            	connect(m_pChatTcpServer, SIGNAL(acceptError(QAbstractSocket::SocketError)), this, SLOT(chatServerError(QAbstractSocket::SocketError)));
            
            	m_pChatTcpServer->listen(QHostAddress::Any, static_cast<quint16>(m_settings.chatPort));
            

            And where I get a newConnection:

            // Called when a new chat connection comes in without us asking for it (m_pChatTcpServer)
            void MainWindow::chatNewConnection()
            {
            	 SQTcpSocket *socket = static_cast<SQTcpSocket *>(m_pChatTcpServer->nextPendingConnection());
            
            	 // Temporarily connect these signals until I am ready to hand this socket off to my ClientServer object
            	 connect(socket, SIGNAL(readyRead()), this, SLOT(chatReadyRead()),Qt::UniqueConnection);
            	 connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(chatConnectionError(QAbstractSocket::SocketError)),Qt::UniqueConnection);
            	 connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(chatTcpSocketState(QAbstractSocket::SocketState)),Qt::UniqueConnection);
            	 connect(socket, SIGNAL(disconnected()), this, SLOT(chatOnConnectionTerminated()),Qt::ConnectionType(Qt::UniqueConnection));
            	 connect(socket, SIGNAL(connected()), this, SLOT(chatOnConnectionEstablished()),Qt::UniqueConnection);
            }
            

            And then receiving the message form the server

            // Here for convenience in case I ever need it. Does nothing because any ready will be done once the socket is handed off to my ClientServer class
            void MainWindow::chatReadyRead()
            {
            	SQTcpSocket *socket = static_cast<SQTcpSocket *>(sender());
            
            	while(socket->bytesAvailable())
            	{
            		QByteArray receivedData = socket->readAll();
            
            		QDataStream ds1(receivedData.mid(0, 4));
            
            		ds1.setByteOrder(QDataStream::LittleEndian);
            
            		int messageSize;
            		ds1 >> messageSize;
            
            		QDataStream ds2(receivedData.mid(4, 4));
            
            		ds2.setByteOrder(QDataStream::LittleEndian);
            
            		int messageType;
            		ds2 >> messageType;
            
            		switch( messageType)
            		{
            			// Initial hand shaking message
            			case CHATMESSAGE_HELLO:
            			{
            				QString uuid, nameColour, nickName;
            
            				uuid = receivedData.mid(8, 32);
            
            				nameColour = receivedData.mid(40, 7);
            				nickName = receivedData.mid(47, -1);
            
            				// Reply back with my initial HELLO (using the same uuid so we both appear in the correct chat tab) message with the nick name colour and nick name
            				unsigned int messageType = CHATMESSAGE_HELLO;
            
            				QByteArray l_vDataToBeSent;
            
            				QDataStream l_vStream(&l_vDataToBeSent, QIODevice::WriteOnly);
            
            				l_vStream.setByteOrder(QDataStream::LittleEndian);
            
            				unsigned int size = sizeof(messageType) + static_cast<unsigned int>(m_settings.nickNameColour.length()) + static_cast<unsigned int>(m_settings.nickName.length()) + static_cast<unsigned int>(uuid.length());
            
            				l_vStream << size;
            
            				l_vStream << messageType;
            
            				l_vDataToBeSent.append(uuid);
            				l_vDataToBeSent.append(m_settings.nickNameColour);
            				l_vDataToBeSent.append(m_settings.nickName);
            
            				if ( socket ) socket->write(l_vDataToBeSent, l_vDataToBeSent.length());
            
            				// Now start the new chat
            				startNewChat( socket, uuid, nameColour, nickName );
            
            				break;
            			}
            		}
            	}
            }
            

            Thanks in advance guys, I think I am totally missing how this works here.

            Regards,

            Steve Q.

            aha_1980A Offline
            aha_1980A Offline
            aha_1980
            Lifetime Qt Champion
            wrote on last edited by aha_1980
            #5

            @steveq You cannot have multiple maschines with the same IP in one network.

            NAT port forwarding still works with one server port only. The trick with port forwarding is, that different client IP addresses are mapped to one address (the NAT routers address), but different client ports.

            For your server, thats transparent.

            Edit: clarified port forwarding more

            Qt has to stay free or it will die.

            1 Reply Last reply
            0
            • S Offline
              S Offline
              steveq
              wrote on last edited by
              #6

              @aha_1980 okay, so I have two versions of my software running on two different machines both with unique LAN IP addresses (192.168.1.2 and 192.168.1.3), but the static IP address for my premises on the internet is provided by my ISP (1.2.3.4) and is the same for both machines, that is if you Google whatismyipaddress, they both have the same "internet" address, but unique LAN addresses. The NAT in the router won't let me forward my chat port (7770) to them both, and even if it did, both machines would get the one message.

              This is doing my head in!! Lol

              Sorry again in advance, I seem to be making this harder than it need to be.

              Steve Q.

              aha_1980A 1 Reply Last reply
              0
              • Kent-DorfmanK Offline
                Kent-DorfmanK Offline
                Kent-Dorfman
                wrote on last edited by Kent-Dorfman
                #7

                I think the thing you don't make clear is your chat architecture. Is it a chat mesh network, or a single master server and multiple clients that all go thru that server? That is the configuration you need to implement. Having multiple chat servers is going to gum up things. You need one master/server that manages and rebroadcasts to relevant clients.

                Rather than worrying about implementation details you need to formalize your system architecture first.

                1 Reply Last reply
                3
                • S steveq

                  @aha_1980 okay, so I have two versions of my software running on two different machines both with unique LAN IP addresses (192.168.1.2 and 192.168.1.3), but the static IP address for my premises on the internet is provided by my ISP (1.2.3.4) and is the same for both machines, that is if you Google whatismyipaddress, they both have the same "internet" address, but unique LAN addresses. The NAT in the router won't let me forward my chat port (7770) to them both, and even if it did, both machines would get the one message.

                  This is doing my head in!! Lol

                  Sorry again in advance, I seem to be making this harder than it need to be.

                  Steve Q.

                  aha_1980A Offline
                  aha_1980A Offline
                  aha_1980
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  @steveq you should draw yourself a topology picture and understand how the data flow is.

                  Remember that port forwarding is only for the server.

                  The client establishes a connection to 1.2.3.4, which is an internet address so the packet leaves your local net. then your router sends the packet back into your local net to the server (which does not even know the clien is next to him!). the answers then goes the other way round.

                  Note that multiple clients and one server can run on the same machine!

                  Qt has to stay free or it will die.

                  1 Reply Last reply
                  3
                  • S Offline
                    S Offline
                    steveq
                    wrote on last edited by
                    #9

                    Hey Guys,

                    Firstly thanks so much for your help.

                    My software is both the server and client in the one package, which now appears to be the source of my problems. In saying that I don’t have the luxury of having a dedicated machine where I can have a server running 24/7. In the future I may look at re-writing my code and have a server running on a Raspberry Pi that I have. If I do that, I guess I’ll need two programs, the chat server and the chat client.

                    In its current form it’s running really well, even allowing multiple clients in the one chat as well as running others chats concurrently. It suits the purpose for which I wrote it, apart from this current issue, which I can “hack” to work if I really want to.

                    From what I understand, the better approach would be where I have a client which connects to a dedicated server and then passes the chat onto the receiving client. All communication then goes through the server.

                    Thanks for everything guys, I really appreciate your help!

                    Steve Q

                    1 Reply Last reply
                    1
                    • KillerSmathK Offline
                      KillerSmathK Offline
                      KillerSmath
                      wrote on last edited by
                      #10

                      @steveq
                      Just as an add-on, you can think of two ways to model a client-server architecture.
                      Centralized and Distributed.
                      Both have their advantages and desvatangens, and all will depend on the purpose of your application.
                      If your application has to provide transparency to the user, whether it is about access (no matter which server I am "connected") or fails (one of the servers is offline), you may have to rethink in a distributed approach.

                      @Computer Science Student - Brazil
                      Web Developer and Researcher
                      “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

                      1 Reply Last reply
                      0
                      • S Offline
                        S Offline
                        steveq
                        wrote on last edited by
                        #11

                        Thanks @KillerSmath, it appears I have a little more reading to do! :-)

                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved