PDA

View Full Version : tcp server poblem



saman_artorious
3rd August 2013, 08:39
I get problems when I want to convert my client program which receives an image size and contents to server program. The client program works properly:


void Client::readFortune()
{
QDataStream in(tcpSocket);

if (blockSize == 0) {
if (tcpSocket->bytesAvailable() < (int)sizeof(quint32))
return;

in >> blockSize;

qDebug() << blockSize;
}

if (tcpSocket->bytesAvailable() < blockSize)
return;

QByteArray nextFortune;
in >> nextFortune;

if (nextFortune == currentFortune) {
QTimer::singleShot(0, this, SLOT(requestNewFortune()));
return;
}

currentFortune = nextFortune;
statusLabel->setText(currentFortune);
getFortuneButton->setEnabled(true);

QImage image;
image.loadFromData(nextFortune);

imageLabel->setPixmap(QPixmap::fromImage(image));
}


However, when I convert client to server the size it gets is wrong. is there anything wrong with the logic of below server program?



void Server::sendFortune()
{
clientConnection = tcpServer->nextPendingConnection();

connect(clientConnection, SIGNAL(disconnected()),
clientConnection, SLOT(deleteLater()));

blockSize = 0;

connect(clientConnection, SIGNAL(readyRead()), this, SLOT(recvFortune()));
}

void Server::recvFortune()
{
QDataStream in(clientConnection);

if (blockSize == 0) {
if (clientConnection->bytesAvailable() < (int) sizeof(quint32))
return;

in >> blockSize;

qDebug() << blockSize;
}

if (clientConnection->bytesAvailable() < blockSize)
return;

QByteArray nextFortune;
in >> nextFortune;

if (nextFortune == currentFortune) {
QTimer::singleShot(0, this, SLOT(requestNewFortune()));
return;
}

QString fileName = "/home/saman/Desktop/png/dest.png";
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) return;
file.write(nextFortune);
file.close();

currentFortune = nextFortune;
statusLabel->setText(currentFortune);

QImage image;
image.loadFromData(nextFortune);

imageLabel->setPixmap(QPixmap::fromImage(image));
}

wysota
3rd August 2013, 10:11
In what way it is "wrong"?

Your app is bound to fail when the peer tries to send a second image but the first block of data should work, assuming you preinitialized blockSize to 0.

saman_artorious
3rd August 2013, 10:44
In what way it is "wrong"?

Your app is bound to fail when the peer tries to send a second image but the first block of data should work, assuming you preinitialized blockSize to 0.

It reads the image size as 506724864, a very large number. Besides, it does not even read the contents. As the same logic runs properly in the client program, I am wondering if I've done something wrong in the server program.




#include <QtWidgets>
#include <QtNetwork>

#include <stdlib.h>

#include "server.h"

Server::Server(QWidget *parent)
: QDialog(parent), tcpServer(0), networkSession(0)
{
statusLabel = new QLabel;
quitButton = new QPushButton(tr("Quit"));
quitButton->setAutoDefault(false);

QNetworkConfigurationManager manager;
if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequir ed) {
// Get saved network configuration
QSettings settings(QSettings::UserScope, QLatin1String("QtProject"));
settings.beginGroup(QLatin1String("QtNetwork"));
const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString();
settings.endGroup();

// If the saved network configuration is not currently discovered use the system default
QNetworkConfiguration config = manager.configurationFromIdentifier(id);
if ((config.state() & QNetworkConfiguration::Discovered) !=
QNetworkConfiguration::Discovered) {
config = manager.defaultConfiguration();
}

networkSession = new QNetworkSession(config, this);
connect(networkSession, SIGNAL(opened()), this, SLOT(sessionOpened()));

statusLabel->setText(tr("Opening network session."));
networkSession->open();
} else {
sessionOpened();
}

fortunes << tr("You've been leading a dog's life. Stay off the furniture.")
<< tr("You've got to think about tomorrow.")
<< tr("You will be surprised by a loud noise.")
<< tr("You will feel hungry again in another hour.")
<< tr("You might have mail.")
<< tr("You cannot kill time without injuring eternity.")
<< tr("Computers are not intelligent. They only think they are.");

connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendFortune()));

QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch(1);
buttonLayout->addWidget(quitButton);
buttonLayout->addStretch(1);

QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(statusLabel);
mainLayout->addLayout(buttonLayout);
setLayout(mainLayout);

setWindowTitle(tr("Fortune Server"));
}

void Server::sessionOpened()
{
// Save the used configuration
if (networkSession) {
QNetworkConfiguration config = networkSession->configuration();
QString id;
if (config.type() == QNetworkConfiguration::UserChoice)
id = networkSession->sessionProperty(QLatin1String("UserChoiceConfiguration")).toString();
else
id = config.identifier();

QSettings settings(QSettings::UserScope, QLatin1String("QtProject"));
settings.beginGroup(QLatin1String("QtNetwork"));
settings.setValue(QLatin1String("DefaultNetworkConfiguration"), id);
settings.endGroup();
}

tcpServer = new QTcpServer(this);
if (!tcpServer->listen()) {
QMessageBox::critical(this, tr("Fortune Server"),
tr("Unable to start the server: %1.")
.arg(tcpServer->errorString()));
close();
return;
}
QString ipAddress;
QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
// 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())
ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
statusLabel->setText(tr("The server is running on\n\nIP: %1\nport: %2\n\n"
"Run the Fortune Client example now.")
.arg(ipAddress).arg(tcpServer->serverPort()));
}

void Server::sendFortune()
{
clientConnection = tcpServer->nextPendingConnection();

connect(clientConnection, SIGNAL(disconnected()),
clientConnection, SLOT(deleteLater()));

blockSize = 0;

connect(clientConnection, SIGNAL(readyRead()), this, SLOT(recvFortune()));
}

void Server::recvFortune()
{
QDataStream in(clientConnection);

if (blockSize == 0) {
if (clientConnection->bytesAvailable() < (int) sizeof(quint32))
return;

in >> blockSize;

qDebug() << blockSize;
}

if (clientConnection->bytesAvailable() < blockSize)
return;

QByteArray nextFortune;
in >> nextFortune;

qDebug() << nextFortune;

if (nextFortune == currentFortune) {
QTimer::singleShot(0, this, SLOT(requestNewFortune()));
return;
}

QString fileName = "/home/saman/Desktop/png/dest.png";
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) return;
file.write(nextFortune);
file.close();

currentFortune = nextFortune;
statusLabel->setText(currentFortune);

QImage image;
image.loadFromData(nextFortune);

imageLabel->setPixmap(QPixmap::fromImage(image));

blockSize = 0;
}

wysota
3rd August 2013, 23:49
I'm not sure if repeating what I (or others) have said in this forum in dozens of other threads regarding TCP connections makes any sense. I can think of a myriad of ways your code is going to fail. One of them is to connect to the "server" with two clients at the same time and try to make them send images to the server.

So instead of repeating the same thing all over again (you can search the forums for similar problems), I am just going to say that your code is inherently wrong and will continue to be wrong unless you first devote yourself to understanding how a network connection between two peers works.

I don't even want to think why you called your QDialog subclass "Server"...