Results 1 to 7 of 7

Thread: Implementing a Fortune Server

  1. #1
    Join Date
    Apr 2014
    Posts
    116
    Thanks
    8
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Implementing a Fortune Server

    Hi there,

    I am trying to add a server feature to my project. My idea was to have the clients sent information to the server. These information are processed and displayed by the server. The server user needs to react on the information he gets from the clients or request more information. Actually I think the whole thing can be seen as an instant messaging system since server and client will be handled by a user.

    To realize that I looked around and found the fortune server/client examples. So I just copied the code from server.h and server.cpp into my code and added "network" to Qt.
    The code compiles without any errors but the program crashes right at the start. I do not get any error messages besides that it crashed.
    This is the line that makes the trouble:
    Qt Code:
    1. // Start Server
    2. QNetworkConfigurationManager manager;
    3. qDebug() << "Hello Server!";
    4. if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) {
    5. qDebug() << "Are you starting";
    To copy to clipboard, switch view to plain text mode 
    Hello Server appears in the console but are you starting not. The else statement is also not triggered. So I assume the if statement makes the trouble.
    qDebug() << manager.capabilities(); gives me QFlags(0x10)

    What could I have possibly missed? Where should I start looking?
    The software I am writing for shall run on OS X. If I am running the example as stand alone it worked after I added #include <QWidget> to the .h file.

    Any hints would be appreciated.

  2. #2
    Join Date
    Apr 2014
    Posts
    116
    Thanks
    8
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Implementing a Fortune Server

    Okay, I tried several things to get what I want but so far it is only partly working. I try to peace together the parts that I found on the web to get a client and a sever code that could be added to an existing project. Goal is to get two programs talking to each other. My sources are the link and the chatterbox example. Hopefully some of you can contribute to it so that there is an example code at the end of this.

    First the sever part. Code needs to be added to your project:
    xy.pro (Server)
    Qt Code:
    1. QT +=network
    To copy to clipboard, switch view to plain text mode 

    mainwindow.h (Server)
    Qt Code:
    1. #include <QTcpSocket>
    2. #include <QTcpServer>
    3. #include <QNetworkInterface>
    4. #include <QRegExp>
    5. [...]
    6. private slots:
    7. void readyRead();
    8. void disconnected();
    9. void incomingConnection();
    10.  
    11. [...]
    12. private:
    13. //Server
    14. QTcpServer *tcpServer;
    15. QSet<QTcpSocket*> clients;
    16. QMap<QTcpSocket*,QString> users;
    To copy to clipboard, switch view to plain text mode 

    mainwindow.cpp (Server)
    Qt Code:
    1. MainWindow::MainWindow(QWidget *parent) :
    2. QMainWindow(parent),
    3. ui(new Ui::MainWindow){
    4.  
    5. ui->setupUi(this);
    6.  
    7. // Server
    8. tcpServer = new QTcpServer(this);
    9. if (!tcpServer->listen()) {
    10. QMessageBox::critical(this, tr("Server Error"), tr("The server could not be started: %1.").arg(tcpServer->errorString()));
    11. close();
    12. return;
    13. }
    14.  
    15. QString ipAddress;
    16. QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
    17. // use the first non-localhost IPv4 address
    18. for (int i = 0; i < ipAddressesList.size(); ++i) {
    19. if (ipAddressesList.at(i) != QHostAddress::LocalHost && ipAddressesList.at(i).toIPv4Address()) {
    20. ipAddress = ipAddressesList.at(i).toString();
    21. break;
    22. }
    23. }
    24.  
    25. // if we did not find one, use IPv4 localhost
    26. if (ipAddress.isEmpty())
    27. ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
    28. // output you need to know the IP and the port the server listens to
    29. qDebug() << ipAddress << tcpServer->serverPort();
    30. connect(tcpServer, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
    31. [...]
    32. }
    33.  
    34. // Server Functions and Slots
    35. void MainWindow::incomingConnection(){
    36. QTcpSocket *client = tcpServer->nextPendingConnection();
    37. // client->setSocketDescriptor(socketfd); <- this is from the original code not sure if I need it or not and where to get the socketfd.
    38. clients.insert(client);
    39.  
    40. qDebug() << "New client from:" << client->peerAddress().toString();
    41.  
    42. connect(client, SIGNAL(readyRead()), this, SLOT(readyRead()));
    43. connect(client, SIGNAL(disconnected()), this, SLOT(disconnected()));
    44. }
    45.  
    46. void MainWindow::readyRead(){
    47. QTcpSocket *client = (QTcpSocket*)sender();
    48. while(client->canReadLine()) {
    49. QString line = QString::fromUtf8(client->readLine()).trimmed();
    50. qDebug() << "Read line:" << line;
    51.  
    52. QRegExp meRegex("^/me:(.*)$");
    53.  
    54. if(meRegex.indexIn(line) != -1){
    55. QString user = meRegex.cap(1);
    56. users[client] = user;
    57. }else if(users.contains(client)){
    58. QString message = line;
    59. QString user = users[client];
    60. qDebug() << "User:" << user;
    61. qDebug() << "Message:" << message;
    62. }else{
    63. qWarning() << "Got bad message from client:" << client->peerAddress().toString() << line;
    64. }
    65. }
    66. }
    67.  
    68. void MainWindow::disconnected(){
    69. QTcpSocket *client = (QTcpSocket*)sender();
    70. clients.remove(client);
    71. QString user = users[client];
    72. users.remove(client);
    73. qDebug() << "Lost connection to Client: << user << client->peerAddress().toString());
    74. }
    75. // End Server Functions and Slots
    To copy to clipboard, switch view to plain text mode 

    And the code on the client side:
    xy.pro
    Qt Code:
    1. QT += network
    To copy to clipboard, switch view to plain text mode 
    mainwindow.h (Client)
    Qt Code:
    1. #include <QTcpSocket>
    2. #include <QtNetwork>
    3. [...]
    4. private slots:
    5. void connectToServer();
    6. void readyRead();
    7. void connected();
    8. void displayError(QAbstractSocket::SocketError socketError);
    9. void enableGetFortuneButton();
    10. void sessionOpened();
    11.  
    12. void on_connectButton_clicked();
    13. [...]
    14.  
    15. private:
    16. Ui::MainWindow *ui;
    17.  
    18. // Client
    19. QTcpSocket *tcpSocket;
    20. QNetworkSession *networkSession;
    21. void sentMSG(QString msg);
    To copy to clipboard, switch view to plain text mode 
    mainwindow.ui (Client) needs to have to inputs for the Server IP and the server port plus an connect button. To display messages a window is also required.

    mainwindow.cpp (Client)
    Qt Code:
    1. MainWindow::MainWindow(QWidget *parent) :
    2. QMainWindow(parent),
    3. ui(new Ui::MainWindow){
    4. ui->setupUi(this);
    5. // Setup Client
    6. // find out which IP to connect to
    7. QString ipAddress;
    8. QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
    9. // use the first non-localhost IPv4 address
    10. for (int i = 0; i < ipAddressesList.size(); ++i) {
    11. if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
    12. ipAddressesList.at(i).toIPv4Address()) {
    13. ipAddress = ipAddressesList.at(i).toString();
    14. break;
    15. }
    16. }
    17. // if we did not find one, use IPv4 localhost
    18. if (ipAddress.isEmpty())
    19. ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
    20.  
    21. tcpSocket = new QTcpSocket(this);
    22.  
    23. connect(ui->hostLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableConnectButton()));
    24. connect(ui->portLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableConnectButton()));
    25. connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readReady()));
    26. connect(tcpSocket, SIGNAL(connected()), this, SLOT(connected()));
    27. connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
    28. }
    29.  
    30. // Network Functions
    31. void MainWindow::on_connectButton_clicked(){
    32. connectToServer();
    33. }
    34.  
    35. void MainWindow::sentMSG(QString msg){
    36. msg = msg.trimmed();
    37. qint64 bytes = 0;
    38. if(!msg.isEmpty())
    39. bytes = tcpSocket->write(msg.toUtf8());
    40.  
    41. if(bytes == -1)
    42. qDebug() << "Error while sending data";
    43. else
    44. qDebug() << bytes << "sent.";
    45. }
    46. void MainWindow::connected(){
    47. // And send our username to the chat server.
    48. sentMSG("/me:"+clientName+"\n");
    49. }
    50. // End Network Functions
    51. //Slots
    52. void MainWindow::connectToServer(){
    53. ui->connectButton->setEnabled(false);
    54. tcpSocket->abort();
    55. tcpSocket->connectToHost(ui->hostLineEdit->text(), ui->portLineEdit->text().toInt());
    56. }
    57.  
    58. void MainWindow::readReady(){
    59. while(tcpSocket->canReadLine()){
    60. QString line = QString::fromUtf8(tcpSocket->readLine()).trimmed();
    61.  
    62. // Using QRegExp allows us to specify different types of messages. Normal messges look like this: "username:The message"
    63. QRegExp messageRegex("^([^:]+):(.*)$");
    64.  
    65. if(messageRegex.indexIn(line) != -1){
    66. QString user = messageRegex.cap(1);
    67. QString message = messageRegex.cap(2);
    68.  
    69. ui->log->append("<b>" + user + "</b>: " + message);
    70. }else{
    71. aDebug() << "Bad message.";
    72. }
    73. }
    74. }
    75. void MainWindow::displayError(QAbstractSocket::SocketError socketError){
    76. switch (socketError) {
    77. case QAbstractSocket::RemoteHostClosedError:
    78. break;
    79. case QAbstractSocket::HostNotFoundError:
    80. QMessageBox::information(this, tr("Fortune Client"),
    81. tr("The host was not found. Please check the "
    82. "host name and port settings."));
    83. break;
    84. case QAbstractSocket::ConnectionRefusedError:
    85. QMessageBox::information(this, tr("Fortune Client"),
    86. tr("The connection was refused by the peer. "
    87. "Make sure the fortune server is running, "
    88. "and check that the host name and port "
    89. "settings are correct."));
    90. break;
    91. default:
    92. QMessageBox::information(this, tr("Fortune Client"),
    93. tr("The following error occurred: %1.")
    94. .arg(tcpSocket->errorString()));
    95. }
    96.  
    97. ui->connectButton->setEnabled(true);
    98. }
    99.  
    100. void MainWindow::enableConnectButton(){
    101. ui->connectButton->setEnabled(!ui->hostLineEdit->text().isEmpty() && !ui->portLineEdit->text().isEmpty());
    102.  
    103. }
    To copy to clipboard, switch view to plain text mode 

    So for the code can connect to the server but messages from the client to the server are ignored. I get the information that the message was sent but the server does not react to it.

    There are probably tons of errors in here. So I would be grateful if some could help me clean up.

    Thanks.
    Last edited by KeineAhnung; 18th June 2014 at 14:43.

  3. #3
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,419
    Thanks
    37
    Thanked 1,546 Times in 1,496 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Implementing a Fortune Server

    The incomingConnection() slot is wrong.

    It creates an unconnected QTcpSocket, it should be retrieving the server side end point of the incoming client connection using QTcpServer::nextPendingConnection().

    Basically instead of
    Qt Code:
    1. QTcpSocket *client = new QTcpSocket(this);
    To copy to clipboard, switch view to plain text mode 
    you have
    Qt Code:
    1. QTcpSocket *client = tcpServer->nextPendingConnection();
    To copy to clipboard, switch view to plain text mode 

    Cheers,
    _

  4. #4
    Join Date
    Apr 2014
    Posts
    116
    Thanks
    8
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Implementing a Fortune Server

    Thank you for the hint. I corrected that in the previous post. Now the line qDebug() "New client from:"... gives me the correct IP of the client but messages are still ignored.

    If line 44 in mainwindow.cpp (Client) put out "24 bytes" does this mean that the server received the message or only the the whole message was sent by the client?

    [edit]
    Okay, I build some minimal programs using the code. So far they work with one exception, message from the client to the server are ignored. I think there is something wrong with connect(client, SIGNAL(readyRead()), this, SLOT(readyRead())); but I cannot figure out what. Can anyone tell me where the mistake is?

    Thanks
    Attached Files Attached Files
    Last edited by KeineAhnung; 18th June 2014 at 17:17.

  5. #5
    Join Date
    Apr 2014
    Posts
    116
    Thanks
    8
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Implementing a Fortune Server

    I have tried a little bit more to figure this out but without any success. How can I trouble shout this? Is it possible to see what information is sent to the server and what the server does with it? How can I check that the right connection is made?

    Thanks

  6. #6
    Join Date
    May 2012
    Posts
    136
    Thanks
    2
    Thanked 27 Times in 24 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Implementing a Fortune Server

    The problem is not with the server, its in the client. in the function sentMSG you use msg = msg.trimmed() this also removes the \n
    socket->canReadLine() expects an \n else it stays false.
    to solve it change the trim or add an \n after the trim, if you dont want to use line endings you should use socket->bytesAvailable() instead of socket->canReadLine()

  7. #7
    Join Date
    Apr 2014
    Posts
    116
    Thanks
    8
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Implementing a Fortune Server

    Thanks, you were right. Good that I know what I am doing here ;-)

Similar Threads

  1. Replies: 0
    Last Post: 27th November 2011, 12:15
  2. qtservice based on threaded fortune server
    By raj_iv in forum Qt Programming
    Replies: 1
    Last Post: 27th May 2011, 13:58
  3. Fortune Server example
    By babu198649 in forum Newbie
    Replies: 2
    Last Post: 19th February 2011, 10:04
  4. Trouble Applying the Fortune Threaded Server
    By dhice in forum Qt Programming
    Replies: 7
    Last Post: 18th April 2009, 23:04

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.