Results 1 to 8 of 8

Thread: Problem encountered in http server implementation

  1. #1
    Join Date
    May 2010
    Posts
    46
    Thanks
    3
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt/Embedded
    Platforms
    Symbian S60

    Exclamation Problem encountered in http server implementation

    I am writing a simple multithreaded Http server using QTcpServer. The server spawns a new thread for every client connection. The new thread is being created in a slot connected to the readyRead() signal.


    Qt Code:
    1. void serverwindow::AcceptClientConn()
    2. {
    3. ui->textEdit->append("\nNew client connection received");
    4.  
    5. clientConnection = tcpServer->nextPendingConnection();
    6.  
    7. ui->textEdit->append("\nNew client connection socketobtained");
    8.  
    9. connect(clientConnection, SIGNAL(disconnected()),
    10. clientConnection, SLOT(deleteLater()));
    11.  
    12. connect( clientConnection, SIGNAL(readyRead()),
    13. this, SLOT(readClient()) );
    14. }
    15.  
    16. void serverwindow::readClient()
    17. {
    18. //read the data obtained from client
    19.  
    20. ui->textEdit->append("\nreadClient");
    21. QTcpSocket* clientSocket = (QTcpSocket*)sender();
    22.  
    23. //create new thread to handle the client request
    24. clienthandler* clientThread = new clienthandler( clientSocket );
    25.  
    26. connect( clientThread,SIGNAL(finished()),
    27. clientThread,SLOT(deleteLater()) );
    28. clientThread->start();
    29. clientThread->setPriority(QThread::HighestPriority);
    30.  
    31. }
    To copy to clipboard, switch view to plain text mode 


    The clienthandle is a subclass of QThread. Its implementation of run() method is as below -

    Qt Code:
    1. void clienthandler::run()
    2. {
    3. clientConnSocket->moveToThread(QThread::currentThread());
    4. if(clientConnSocket->canReadLine())
    5. {
    6. QString curData(clientConnSocket->readLine());
    7. QStringList tokens = curData.split(QRegExp("[ \r\n][ \r\n]*"));
    8. if ( tokens[0] == "GET" )
    9. {
    10. //try to send a file's contents
    11.  
    12. //1. Small sized html file
    13. QFile htmlfile("c:\\server_files\\index.html");
    14.  
    15. if (!htmlfile.open(QIODevice::ReadOnly))
    16. return;
    17.  
    18. QString content_type = "video/mp4;";
    19. QTextStream os( clientConnSocket );
    20. //os.setAutoDetectUnicode(true);
    21. os << "HTTP/1.0 200 Ok\r\n"
    22. "Content-Type: "<< content_type <<"charset=\"utf-8\"\r\n"
    23. "\r\n";
    24. os.flush();
    25.  
    26. // Streaming the file
    27. QByteArray block = htmlfile.readAll();
    28. clientConnSocket->write(block);
    29. }
    30. }
    31. clientConnSocket->disconnectFromHost();
    32. clientConnSocket->close();
    33. }
    To copy to clipboard, switch view to plain text mode 



    When i run the server, it receives client connections but issues the following error -

    QObject::moveToThread: Cannot move objects with a parent
    QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QNativeSocketEngine(0x9640878), parent's thread is QThread(0x3d59e8), current thread is clienthandler(0x9644cb0)
    QSocketNotifier: socket notifiers cannot be disabled from another thread



    What changes should i make in the code to avoid these errors ? I know its the problem with the socket reference being passed to the new thread , but how else can I do it ? I know this question has been asked in this forum a lot many times, but I could not find a suitable answer.

  2. #2
    Join Date
    Jan 2006
    Location
    Belgium
    Posts
    1,938
    Thanked 268 Times in 268 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Wiki edits
    20

    Default Re: Problem encountered in http server implementation

    Quote Originally Posted by ada10 View Post
    What changes should i make in the code to avoid these errors ?
    Don't use threads. Yes, I'm serious.

    I know its the problem with the socket reference being passed to the new thread , but how else can I do it ?
    The problem with threads is that you really need to know which code is being run inside which thread.
    Your code mixes the code beyond any computer being capable of understanding it :-) Just kidding, but the structure isn't clean or clear.

    If I would use threads for a server I would create a socket object, just a simple QObject that you use like any other object. You can connect signals and slots like you do with any normal object.
    Then, you move this object to a new thread.

    Qt Code:
    1. class MySuperHTTPSocket : public QTcpSocket
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. ...
    7.  
    8. public slots:
    9. void mySlot1();
    10.  
    11. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. void MySuperHTTPServer::handleIncommingConnection(...)
    2. {
    3. MySuperHTTPSocket *socket = new MySuperHTTPSocket;
    4.  
    5. connect(socket, SIGNAL, this, SLOT);
    6. connect(this, SIGNAL, socket, SLOT);
    7.  
    8. QThread *socketThread = new QThread;
    9.  
    10. socket->moveToThread(socketThread);
    11. socketThread->start();
    12. }
    To copy to clipboard, switch view to plain text mode 

    Or something like that.

  3. #3
    Join Date
    May 2010
    Posts
    46
    Thanks
    3
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt/Embedded
    Platforms
    Symbian S60

    Exclamation Re: Problem encountered in http server implementation

    Okay, I tried something similar to the Threaded Fortune server example. The end result of the code was this -


    hostingserver.h ( subclass of QTcpserver )

    Qt Code:
    1. class hostingserver : public QTcpServer {
    2. Q_OBJECT
    3. public:
    4. hostingserver(QObject *parent = 0);
    5. ~hostingserver();
    6.  
    7. protected:
    8. void incomingConnection(int socketDescriptor);
    9.  
    10. private:
    11.  
    12. };
    To copy to clipboard, switch view to plain text mode 

    hostingserver.cpp -

    Qt Code:
    1. hostingserver::hostingserver(QObject *parent) :
    2. QTcpServer(parent)
    3. {
    4.  
    5. }
    6.  
    7. hostingserver::~hostingserver()
    8. {
    9.  
    10. }
    11.  
    12. void hostingserver::incomingConnection(int socketDescriptor)
    13. {
    14.  
    15. clienthandler *thread = new clienthandler(socketDescriptor,this);
    16. connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    17. thread->start();
    18. }
    To copy to clipboard, switch view to plain text mode 

    the clienthandler is a QThread -

    Qt Code:
    1. class clienthandler : public QThread
    2. {
    3. Q_OBJECT
    4. public:
    5. clienthandler(int socketDescriptor, QObject *parent);
    6.  
    7. ~clienthandler();
    8.  
    9. public: //implemented from QRunnable
    10. void run();
    11.  
    12. signals:
    13. void error(QTcpSocket::SocketError socketError);
    14.  
    15. private:
    16. int socketDescriptor;
    17.  
    18. };
    To copy to clipboard, switch view to plain text mode 


    clienthandler implementation -

    Qt Code:
    1. clienthandler::clienthandler(
    2. int aSocketDescriptor,QObject *parent) :
    3. QThread(parent),socketDescriptor(aSocketDescriptor)
    4. {
    5.  
    6. }
    7.  
    8. clienthandler::~clienthandler()
    9. {
    10.  
    11. }
    12.  
    13. void clienthandler::run()
    14. {
    15. QFile fn("c:\\server_files\\server_log.txt");
    16. fn.open(QIODevice::WriteOnly | QIODevice::Text);
    17. fn.write(QString("run impl called").toAscii());
    18. QTcpSocket clientConnSocket;
    19.  
    20. if (!clientConnSocket.setSocketDescriptor(socketDescriptor)) {
    21. emit error(clientConnSocket.error());
    22. return;
    23. }
    24.  
    25. fn.write(QString("\nsetSocketDescriptor called").toAscii());
    26.  
    27. bool isCorrect = clientConnSocket.canReadLine();
    28. if( !isCorrect )
    29. fn.write(QString("\nLine cannot be read").toAscii());
    30. if(clientConnSocket.canReadLine())
    31. {
    32. QString curData(clientConnSocket.readLine());
    33. QStringList tokens = curData.split(QRegExp("[ \r\n][ \r\n]*"));
    34. if ( tokens[0] == "GET" )
    35. {
    36. //try to send a file's contents
    37. fn.write(QString("GET obtained").toAscii());
    38. //1. Small sized html file
    39. QFile htmlfile("c:\\server_files\\index.html");
    40.  
    41. if (!htmlfile.open(QIODevice::ReadOnly))
    42. return;
    43.  
    44. QString content_type = "text/html;";
    45. QTextStream os( &clientConnSocket );
    46. //os.setAutoDetectUnicode(true);
    47. os << "HTTP/1.0 200 Ok\r\n"
    48. "Content-Type: "
    49. << content_type
    50. <<"charset=\"utf-8\"\r\n"
    51. <<"\r\n";
    52. os.flush();
    53.  
    54. // Streaming the file
    55. QByteArray block = htmlfile.readAll();
    56. clientConnSocket.write(block);
    57. }
    58. }
    59. clientConnSocket.disconnectFromHost();
    60. fn.close();
    61. }
    To copy to clipboard, switch view to plain text mode 

    clientConnSocket.canReadLine() always returns false in the above code. Whta should I do for this ?

  4. #4
    Join Date
    Jan 2006
    Location
    Belgium
    Posts
    1,938
    Thanked 268 Times in 268 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Wiki edits
    20

    Default Re: Problem encountered in http server implementation

    Quote Originally Posted by ada10 View Post
    clientConnSocket.canReadLine() always returns false in the above code. Whta should I do for this ?
    You try to read from the socket right after sending something.
    There's no time to receive anything yet. You need to wait.

  5. #5
    Join Date
    May 2010
    Posts
    46
    Thanks
    3
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt/Embedded
    Platforms
    Symbian S60

    Default Re: Problem encountered in http server implementation

    I am testing this server using a Firefox and the server running on the same machine. What is the appropriate should the server wait for the request to arrive ?

  6. #6
    Join Date
    Jan 2006
    Location
    Belgium
    Posts
    1,938
    Thanked 268 Times in 268 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Wiki edits
    20

    Default Re: Problem encountered in http server implementation

    Quote Originally Posted by ada10 View Post
    What is the appropriate should the server wait for the request to arrive ?
    That's the wrong question to ask, and here's why:
    You can never know.

    You can set a time out though to, for example, 10 seconds.

    Here are the two techniques to deal with the data:
    1. Asynchronous, or non-blocking. This is event driven. Every time data becomes available, the socket will post an event resulting in a signal (the readyRead signal)
    If you connect a slot to this signal, you can use readLine, or any of the other read functions. In the mean time, the socket will do nothing except checking the buffers and it will not block the event queue.

    2. Synchronous, or blocking. This is not event driven. The socket just waits for data te become available. It blocks the event queue and can almost only be used in threads.
    Use the waitFor...() functions.

    Suggestion: Do not use threads and certainly not the blocking functions unless you absolutely need to.

  7. #7
    Join Date
    May 2010
    Posts
    46
    Thanks
    3
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt/Embedded
    Platforms
    Symbian S60

    Exclamation Re: Problem encountered in http server implementation

    I used both the methods as you mentioned. In the asynchronous method I tried, the code looked like this -

    Qt Code:
    1. clientConnection = tcpServer->nextPendingConnection();
    2.  
    3. connect(clientConnection, SIGNAL(disconnected()),
    4. clientConnection, SLOT(deleteLater()));
    5.  
    6. connect( clientConnection, SIGNAL(readyRead()),
    7. this, SLOT(readClient()) );
    To copy to clipboard, switch view to plain text mode 

    where the readClient() slot implementation is as shown -

    Qt Code:
    1. void serverwindow::readClient()
    2. {
    3. QTcpSocket* clientSocket = (QTcpSocket*)sender();
    4.  
    5. //pass this socket to a new thread which send some data to client
    6. }
    To copy to clipboard, switch view to plain text mode 

    Here as I obtain some data on socket, I used to spawn a new thread with the socket reference as a parameter to the thread. This caused huge problems because that socket reference could not be "moved" to another thread. So this was the issue I faced with the asynchronous method.

    So I used th synchronous method with waitForReadyRead() method with some parameter ( which is not the way code should be written; I understand ).
    Certainly I know, the asynch method is better, but I could not find a solution to the above problem . If you could provide some solution to this, I would be happy to incorporate into my code.

  8. #8
    Join Date
    Jan 2006
    Location
    Belgium
    Posts
    1,938
    Thanked 268 Times in 268 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Wiki edits
    20

    Default Re: Problem encountered in http server implementation

    I'll try to write an example later today.

Similar Threads

  1. Sample of Http server
    By Lele in forum Qt Programming
    Replies: 2
    Last Post: 30th November 2010, 23:43
  2. Qt Http implementation
    By ada10 in forum Newbie
    Replies: 6
    Last Post: 11th August 2010, 23:36
  3. Http server : send images
    By fitzy in forum Qt Programming
    Replies: 1
    Last Post: 2nd November 2009, 12:04
  4. mutithread in http-server
    By chuengchuenghq in forum Qt Programming
    Replies: 1
    Last Post: 8th June 2008, 00:24
  5. Build an HTTP server
    By the_bis in forum Qt Programming
    Replies: 4
    Last Post: 30th March 2007, 07:36

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.