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:
Code:
// Start Server
QNetworkConfigurationManager manager;
qDebug() << "Hello Server!";
if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) {
qDebug() << "Are you starting";
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.
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)
mainwindow.h (Server)
Code:
#include <QTcpSocket>
#include <QTcpServer>
#include <QNetworkInterface>
#include <QRegExp>
[...]
private slots:
void readyRead();
void disconnected();
void incomingConnection();
[...]
private:
//Server
QSet<QTcpSocket*> clients;
QMap<QTcpSocket*,QString> users;
mainwindow.cpp (Server)
Code:
MainWindow
::MainWindow(QWidget *parent
) : ui(new Ui::MainWindow){
ui->setupUi(this);
// Server
if (!tcpServer->listen()) {
QMessageBox::critical(this, tr
("Server Error"), tr
("The server could not be started: %1.").
arg(tcpServer
->errorString
()));
close();
return;
}
// use the first non-localhost IPv4 address
for (int i = 0; i < ipAddressesList.size(); ++i) {
if (ipAddressesList.
at(i
) != QHostAddress::LocalHost && ipAddressesList.
at(i
).
toIPv4Address()) { ipAddress = ipAddressesList.at(i).toString();
break;
}
}
// if we did not find one, use IPv4 localhost
if (ipAddress.isEmpty())
// output you need to know the IP and the port the server listens to
qDebug() << ipAddress << tcpServer->serverPort();
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
[...]
}
// Server Functions and Slots
void MainWindow::incomingConnection(){
QTcpSocket *client
= tcpServer
->nextPendingConnection
();
// client->setSocketDescriptor(socketfd); <- this is from the original code not sure if I need it or not and where to get the socketfd.
clients.insert(client);
qDebug() << "New client from:" << client->peerAddress().toString();
connect(client, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(client, SIGNAL(disconnected()), this, SLOT(disconnected()));
}
void MainWindow::readyRead(){
while(client->canReadLine()) {
qDebug() << "Read line:" << line;
if(meRegex.indexIn(line) != -1){
users[client] = user;
}else if(users.contains(client)){
qDebug() << "User:" << user;
qDebug() << "Message:" << message;
}else{
qWarning() << "Got bad message from client:" << client->peerAddress().toString() << line;
}
}
}
void MainWindow::disconnected(){
clients.remove(client);
users.remove(client);
qDebug() << "Lost connection to Client: << user << client->peerAddress().toString());
}
// End Server Functions and Slots
And the code on the client side:
xy.pro
mainwindow.h (Client)
Code:
#include <QTcpSocket>
#include <QtNetwork>
[...]
private slots:
void connectToServer();
void readyRead();
void connected();
void enableGetFortuneButton();
void sessionOpened();
void on_connectButton_clicked();
[...]
private:
Ui::MainWindow *ui;
// Client
QNetworkSession *networkSession;
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)
Code:
MainWindow
::MainWindow(QWidget *parent
) : ui(new Ui::MainWindow){
ui->setupUi(this);
// Setup Client
// find out which IP to connect to
// use the first non-localhost IPv4 address
for (int i = 0; i < ipAddressesList.size(); ++i) {
ipAddressesList.at(i).toIPv4Address()) {
ipAddress = ipAddressesList.at(i).toString();
break;
}
}
// if we did not find one, use IPv4 localhost
if (ipAddress.isEmpty())
connect(ui
->hostLineEdit,
SIGNAL(textChanged
(QString)),
this,
SLOT(enableConnectButton
()));
connect(ui
->portLineEdit,
SIGNAL(textChanged
(QString)),
this,
SLOT(enableConnectButton
()));
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readReady()));
connect(tcpSocket, SIGNAL(connected()), this, SLOT(connected()));
}
// Network Functions
void MainWindow::on_connectButton_clicked(){
connectToServer();
}
void MainWindow
::sentMSG(QString msg
){ msg = msg.trimmed();
qint64 bytes = 0;
if(!msg.isEmpty())
bytes = tcpSocket->write(msg.toUtf8());
if(bytes == -1)
qDebug() << "Error while sending data";
else
qDebug() << bytes << "sent.";
}
void MainWindow::connected(){
// And send our username to the chat server.
sentMSG("/me:"+clientName+"\n");
}
// End Network Functions
//Slots
void MainWindow::connectToServer(){
ui->connectButton->setEnabled(false);
tcpSocket->abort();
tcpSocket->connectToHost(ui->hostLineEdit->text(), ui->portLineEdit->text().toInt());
}
void MainWindow::readReady(){
while(tcpSocket->canReadLine()){
// Using QRegExp allows us to specify different types of messages. Normal messges look like this: "username:The message"
QRegExp messageRegex
("^([^:]+):(.*)$");
if(messageRegex.indexIn(line) != -1){
QString user
= messageRegex.
cap(1);
QString message
= messageRegex.
cap(2);
ui->log->append("<b>" + user + "</b>: " + message);
}else{
aDebug() << "Bad message.";
}
}
}
switch (socketError) {
break;
tr("The host was not found. Please check the "
"host name and port settings."));
break;
tr("The connection was refused by the peer. "
"Make sure the fortune server is running, "
"and check that the host name and port "
"settings are correct."));
break;
default:
tr("The following error occurred: %1.")
.arg(tcpSocket->errorString()));
}
ui->connectButton->setEnabled(true);
}
void MainWindow::enableConnectButton(){
ui->connectButton->setEnabled(!ui->hostLineEdit->text().isEmpty() && !ui->portLineEdit->text().isEmpty());
}
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.
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
you have
Code:
QTcpSocket *client
= tcpServer
->nextPendingConnection
();
Cheers,
_
2 Attachment(s)
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
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
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()
Re: Implementing a Fortune Server
Thanks, you were right. Good that I know what I am doing here ;-)