Results 1 to 4 of 4

Thread: QTcpSocket, QTcpServer problem

  1. #1
    Join Date
    Jan 2008
    Location
    Slovenia
    Posts
    6
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default QTcpSocket, QTcpServer problem

    I took threaded fortune server example for experimenting with tcp socket communication.

    The idea is to make a server that will accept many clients. When a connected client sends message to server, the server would sent this message to all other connected clients.

    Here is the code so far:
    server.h
    Qt Code:
    1. #ifndef SERVER_H
    2. #define SERVER_H
    3.  
    4. #include <QStringList>
    5. #include <QTcpServer>
    6.  
    7. class Server : public QTcpServer
    8. {
    9. Q_OBJECT
    10.  
    11. public:
    12. Server ( QObject *parent = 0 );
    13.  
    14. protected:
    15. void incomingConnection ( int socketDescriptor );
    16.  
    17. private slots:
    18. void fromClient(QByteArray data);
    19.  
    20. signals:
    21. void toClient(QByteArray data);
    22. };
    23. #endif
    To copy to clipboard, switch view to plain text mode 
    server.cpp:
    Qt Code:
    1. #include "server.h"
    2. #include "serverthread.h"
    3.  
    4. Server::Server ( QObject *parent )
    5. : QTcpServer ( parent )
    6. {
    7. listen ( QHostAddress::Any, 8888 );
    8. }
    9.  
    10. void Server::incomingConnection ( int socketDescriptor )
    11. {
    12. ServerThread *thread = new ServerThread ( socketDescriptor, this );
    13. connect ( thread, SIGNAL ( finished() ), thread, SLOT ( deleteLater() ) );
    14. connect ( thread, SIGNAL ( started() ), thread, SLOT ( threadStarted() ) );
    15. connect ( thread, SIGNAL ( fromClient ( QByteArray ) ), this, SLOT ( fromClient ( QByteArray ) ) );
    16. connect ( this, SIGNAL ( toClient ( QByteArray ) ), thread, SLOT ( toClient ( QByteArray ) ) );
    17. thread->start();
    18. }
    19.  
    20. void Server::fromClient ( QByteArray data )
    21. {
    22. ServerThread* thread = static_cast<ServerThread*> ( sender() );
    23. disconnect ( this, SIGNAL ( toClient ( QByteArray ) ), thread, SLOT ( toClient ( QByteArray ) ) );
    24. emit toClient ( data );
    25. connect ( this, SIGNAL ( toClient ( QByteArray ) ), thread, SLOT ( toClient ( QByteArray ) ) );
    26. }
    To copy to clipboard, switch view to plain text mode 
    serverthread.h:
    Qt Code:
    1. #ifndef SERVERTHREAD_H
    2. #define SERVERTHREAD_H
    3.  
    4. #include <QThread>
    5. #include <QTcpSocket>
    6.  
    7. class ServerThread : public QThread
    8. {
    9. Q_OBJECT
    10.  
    11. public:
    12. ServerThread ( int socketDescriptor, QObject *parent );
    13. ~ServerThread ();
    14.  
    15. void run();
    16.  
    17. signals:
    18. void error ( QTcpSocket::SocketError socketError );
    19. void fromClient(QByteArray data);
    20.  
    21. public slots:
    22. void toClient(QByteArray data);
    23.  
    24. private slots:
    25. void socketDisconnected();
    26. void receiveMessage();
    27. void threadStarted();
    28.  
    29. private:
    30. int socketDescriptor;
    31. QTcpSocket* client;
    32. quint16 blockSize;
    33.  
    34. QByteArray createQByteArray(QString str);
    35. };
    36. #endif
    To copy to clipboard, switch view to plain text mode 
    serverthread.cpp
    Qt Code:
    1. #include "serverthread.h"
    2.  
    3. #include <QtNetwork>
    4.  
    5. ServerThread::ServerThread ( int socketDescriptor, QObject *parent )
    6. : QThread ( parent ), socketDescriptor ( socketDescriptor )
    7. {
    8. blockSize = 0;
    9. }
    10.  
    11. ServerThread::~ServerThread ( )
    12. {
    13. }
    14.  
    15. void ServerThread::run()
    16. {
    17. exec();
    18. }
    19.  
    20. void ServerThread::socketDisconnected()
    21. {
    22. quit();
    23. }
    24.  
    25. void ServerThread::threadStarted()
    26. {
    27. client = new QTcpSocket(this);
    28.  
    29. connect ( client, SIGNAL ( disconnected() ),
    30. this, SLOT ( socketDisconnected() ) );
    31.  
    32. connect ( client, SIGNAL ( readyRead() ),
    33. this, SLOT ( receiveMessage() ) );
    34.  
    35. if ( !client->setSocketDescriptor ( socketDescriptor ) )
    36. {
    37. emit error ( client->error() );
    38. return;
    39. }
    40. }
    41.  
    42. void ServerThread::receiveMessage()
    43. {
    44. QDataStream in ( client );
    45. in.setVersion ( QDataStream::Qt_4_0 );
    46.  
    47. if ( blockSize == 0 )
    48. {
    49. if ( client->bytesAvailable() < ( int ) sizeof ( quint16 ) )
    50. return;
    51.  
    52. in >> blockSize;
    53. }
    54. if ( client->bytesAvailable() < blockSize )
    55. return;
    56.  
    57. QString str;
    58. in >> tmp;
    59. str = QString::fromUtf8 ( qUncompress ( tmp ) );
    60.  
    61. blockSize = 0;
    62.  
    63. emit fromClient ( createQByteArray ( str ) ); //pošljemo vsem ostalim clientom povezanim na server
    64. }
    65.  
    66. QByteArray ServerThread::createQByteArray ( QString str )
    67. {
    68. QByteArray block;
    69. QDataStream out ( &block, QIODevice::WriteOnly );
    70. out.setVersion ( QDataStream::Qt_4_0 );
    71.  
    72. out << ( quint16 ) 0;
    73. out << qCompress ( str.toUtf8(),9 );
    74. out.device()->seek ( 0 );
    75. out << ( quint16 ) ( block.size() - sizeof ( quint16 ) );
    76.  
    77. return block;
    78. }
    79.  
    80. void ServerThread::toClient ( QByteArray data )
    81. {
    82. client->write ( data );
    83. }
    To copy to clipboard, switch view to plain text mode 
    Everithing works well if client sends one message. But if i try to send let say 1000 messages (in for loop), other clients don't receive all messages but random noumber of them. Also all clients don't receive same number of messages.

    Any suggestions?

    tnx

  2. #2
    Join Date
    Jan 2008
    Location
    Slovenia
    Posts
    6
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QTcpSocket, QTcpServer problem

    One more thing...

    I added counter in ServerThread::receiveMessage() slot. I figured out that this slot is not triggered as many times as client sends the message.

    I'm still pulling my hair... Help pls!

  3. #3
    Join Date
    Feb 2009
    Location
    Noida, India
    Posts
    517
    Thanks
    21
    Thanked 66 Times in 62 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QTcpSocket, QTcpServer problem

    perhaps u could use QSignalSpyand with its api, urself make sure that the slot is called as no. of times as wanted..i guess what is happening here is when the same slot is left to be processed for n no. of times, Qt executes only a couple of times and assumes its done..i m not sure though about that though

  4. #4
    Join Date
    Jan 2008
    Location
    Slovenia
    Posts
    6
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QTcpSocket, QTcpServer problem

    I found the problem (and solution)!

    This post was very helpful. Especially this part:
    Qt can only wait until the data has been written to the device. The device is
    the TCP/IP protocol stack of the operating system, not the network wires.

    From that time on it is absolutely out of control of Qt. Since you send just
    20 bytes of data this will probably be accepted by the OS immediatly, making
    waitForBytesWritten return. After that there will only be some microseconds
    in your for-loop when the next bytes get written. So your OS might decide to
    pack all these bytes together and send it as one packet
    . This will at least
    happen with the second and third msg since the first msg is still keeping the
    network wires busy.
    Even if your msgs are send as you write them the receiver might put them all
    together into one big chunk.
    So I changed receiveMessage() a bit assuming kernel could combine many messages together.

    Qt Code:
    1. void ServerThread::receiveMessage()
    2. {
    3. QDataStream in ( this );
    4. in.setVersion ( QDataStream::Qt_4_0 );
    5.  
    6. while ( !in.atEnd() )
    7. {
    8. if ( blockSize == 0 )
    9. {
    10. if ( bytesAvailable() < ( int ) sizeof ( quint16 ) )
    11. return;
    12.  
    13. in >> blockSize;
    14. }
    15.  
    16. if ( bytesAvailable() < blockSize )
    17. return;
    18.  
    19. QString str;
    20. in >> tmp;
    21. str = QString::fromUtf8 ( qUncompress ( tmp ) );
    22.  
    23. blockSize = 0;
    24. emit fromClient ( createQByteArray ( str ) );
    25. }
    26. }
    To copy to clipboard, switch view to plain text mode 

    So... Fortune Client/Server Example works fine as long as you send only one message or many messages at slow speed (pause between messages). If you send messages at high speed (like for loop), the kernel combines them. And you should be prepared for that situation. I think TrollTech should mention it somewhere in example or documentation.

    Thanks everyone for help!

Similar Threads

  1. Challenging QTcpSocket reliability problem
    By Raccoon29 in forum Qt Programming
    Replies: 3
    Last Post: 13th January 2009, 10:38
  2. QTcpServer & QTcpSocket questions...
    By jxmot in forum Qt Programming
    Replies: 2
    Last Post: 24th April 2008, 21:38
  3. Problem with QTcpSocket in QThread
    By Raistlin in forum Qt Programming
    Replies: 8
    Last Post: 6th October 2007, 12:23
  4. Replies: 3
    Last Post: 29th June 2007, 08:32
  5. problem with QTcpSocket
    By SuperSonik in forum Qt Programming
    Replies: 8
    Last Post: 31st January 2007, 16:00

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.