Skip to content

Instantly share code, notes, and snippets.

@lamprosg
Last active February 17, 2019 00:01
Show Gist options
  • Save lamprosg/4461154 to your computer and use it in GitHub Desktop.
Save lamprosg/4461154 to your computer and use it in GitHub Desktop.
TCP/IP Programming (Qt SDK)
void IP::connectToServer() //Connect to the server
{
tcpSocket = new QTcpSocket(this); //Client socket constructor
tcpSocket->connectToHost("100.100.100.100", 3724); //Connect
//OR
//tcpSocket->connectToHost(QHostAddress::LocalHost,6178);
//The only QTcpSocket signals we need are QTcpSocket::readyRead(),
//signifying that data has been received, QTcpSocket::hostFound(),
//this signal is emitted after connectToHost() has been called and the host lookup has succeeded,
//and QTcpSocket::error(), which we will use to catch any connection errors
connect(tcpSocket, SIGNAL(hostFound()), this, SLOT(weAreConnected()));
connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(getFiles()));
connect(tcpSocket, SIGNAL(disconnected()), tcpSocket, SLOT(deleteLater()));
length=0; //Length of bytes read
counter=0;
newfile=true;
buffer=1024*1024; //A chunk of 1MB, we'll be used for buffering
offset = 0;
sizeread=0;
}
void IP::weAreConnected()
{
ui->iplabel->setText("Connected");
}
void IP::displayError(QAbstractSocket::SocketError socketError)
{
switch (socketError)
{
case QAbstractSocket::RemoteHostClosedError:
break;
case QAbstractSocket::HostNotFoundError:
QMessageBox::information(this, tr("IPShare Client"),
tr("The host was not found. Please check the "
"host name and make sure it is sharing."));
break;
case QAbstractSocket::ConnectionRefusedError:
QMessageBox::information(this, tr("IPShare Client"),
tr("The connection was refused by the peer. "
"Make sure the other side is sharing, "
"and check that the host name and port "
"settings are correct."));
break;
default:
QMessageBox::information(this, tr("IPShare Client"),
tr("The following error occurred: %1.")
.arg(tcpSocket->errorString()));
}
delete tcpSocket;
}
void IP::sendSomething()
{
if (savedirectory=="/home/")
{
QMessageBox::question(this, tr("Reminder"),tr("Select a directory for files to be saved first."));
}
else
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly); // we will serialize the data in the array block
out.setVersion(QDataStream::Qt_4_0);
out << (quint16)0; //we reserve space for a 16 bit integer that will contain the total size of the data block we are sending
out << QString( something ); //Sending the name of the file
out.device()->seek(0); //Going back to the beginning of the array
out << (quint16)(block.size() - sizeof(quint16)); //overwrite the reserved 16 bit integer value with the total size of the array
tcpSocket->write(block); //Send message
}
}
void IP::getFiles() //Receiving data
{
//First get the filesize we're going to download
QDataStream in(tcpSocket);
in.setVersion(QDataStream::Qt_4_0);
quint64 blockSize=0;
/*******************Reading the blockSize first in order to know how much data we'll receive***/
if (blockSize == 0)
{
if (tcpSocket->bytesAvailable() < (int)sizeof(quint64))
return;
in >> blockSize;
}
/**********************************************************************************************/
if (tcpSocket->bytesAvailable() < (int) blockSize) //Wait until all the data are received
return;
in >> filesize;
QString path = savedirectory;
path += filenames[counter];
file = new QFile(path); //Create the file
file->open(QIODevice::WriteOnly); //Open it
//Download it in chunks, so the memory won't crash
char *data = new char[buffer];
length = tcpSocket->read(data, buffer); //Buffer 1MB first, max.
file->write(data,length);
sizeread += length;
int value = (sizeread/filesizes[counter])*100;
delete [] data;
if (sizeread == filesize) //File size reached, closing file
{
file->close();
delete file;
counter++;
length=0;
sizeread=0;
}
/*QTcpSocket::disconnectFromHost() will close the connection after QTcpSocket has finished writing
the data to the network. Because QTcpSocket works asynchronously, the data will be written after
this function returns, and control goes back to Qt's event loop.
The socket will then close, which in turn will cause QObject::deleteLater() to delete it.*/
tcpSocket->disconnectFromHost();
/***Client**************************************************************/
QTcpSocket *tcpSocket; //Socket used by the client
bool iwantthem; //Distinguish between getting the list or the actual files
int numberofitems; //How many files are there
QString *filenames; //Individual file names
int filesize; //Individual file sizes
int totalfilesize; //Total size of files
qint64 length; //Length of bytes read
int counter; //File counter
bool newfile;
qint64 buffer;
QFile *file;
qint64 offset;
qint64 sizeread;
QString savedirectory; //Where files are going to be downloaded and saved
/***********************************************************************/
/*Client Slots************************/
void getFiles(); //Get the files
void displayError(QAbstractSocket::SocketError socketError); //Catch connection errors
void weAreConnected(); //When connection is established
/*************************************/
void IP::getAddresses()
{
QNetworkInterface net;
QList<QHostAddress> addresses = net.allAddresses();
QString text;
for (int i=0;i<addresses.size();i++)
{
text+=addresses.value(i).toString();
text+="\n\n";
}
ui->textedit->setText(text);
}
QT += core gui
QT += network
void IP::sekectDir()
{
savedirectory=QFileDialog::getExistingDirectory(this, tr("Select Directory"),
"/home",
QFileDialog::ShowDirsOnly
| QFileDialog::DontResolveSymlinks);
savedirectory += "/";
}
void IP::serverStart()
{
tcpServer = new QTcpServer(this); //tcpServer constructor
if (!tcpServer->isListening())
{
if (!tcpServer->listen(QHostAddress::Any, 3724)) //Start listening (WoW port)
{
QMessageBox::critical(this, tr("IPShare Server"),
tr("Unable to start the server: %1.")
.arg(tcpServer->errorString()));
// close(); //Closes the widget
ui->iplabel->setText("Unable to start the server");
tcpServer->close();
delete tcpServer;
return;
}
//The QTcpServer::newConnection() signal is emitted each time a client connects to the server.
//The ServerRespond() function will be executed each time.
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(ServerRespond()));
}
}
void IP::ServerRespond() //First response to the client
{
ui->iplabel->setText("Client connected");
//we create a QByteArray and a QDataStream object, passing the bytearray to QDataStream's constructor
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly); // we will serialize the data in the array block
//We set the protocol version of QDataStream to QDataStream::Qt_4_0 to ensure that we can communicate with clients from future versions of Qt.
out.setVersion(QDataStream::Qt_4_0);
QString hello_there;
out << (quint64)0; //we reserve space for a 64 bit integer that will contain the total size of the data block we are sending
out << QString(hello_there); //Writing the bytearray
out.device()->seek(0); //Going back to the beginning of the array
out << (quint64)(block.size() - sizeof(quint64)); //overwrite the reserved 64 bit integer value with the total size of the array
/*We call QTcpServer::nextPendingConnection() to accept the connection
and use the returned QTcpSocket to communicate with the client.*/
clientConnection = tcpServer->nextPendingConnection();
clientConnection->write(block); //Sending the item list to the client
ui->iplabel->setText("File list sent");
/*This signal is emitted once every time new data is available for reading from the device.
It will only be emitted again once new data is available,
such as when a new payload of network data has arrived on the network socket,
or when a new block of data has been appended to the device.
TCP is based on sending a stream of data, so we cannot expect to get the entire data in one go.
Especially on a slow network, the data can be received in several small fragments.
QTcpSocket buffers up all incoming data and emits readyRead() for every new block that arrives,
and it is our job to ensure that we have received all the data we need before we start parsing.*/
connect(clientConnection, SIGNAL(readyRead()), this, SLOT(sendFiles()));
/*By connecting QTcpSocket::disconnected() to QObject::deleteLater(),
we ensure that the socket will be deleted after disconnecting.*/
connect(clientConnection, SIGNAL(disconnected()), clientConnection, SLOT(deleteLater()));
}
void IP::sendFiles()
{
//Read somethig and then send a file
quint16 blockSize=0;
QDataStream in(clientConnection);
in.setVersion(QDataStream::Qt_4_0);
/*******************Reading the blockSize first in order to know how much data we'll receive***/
if (blockSize == 0)
{
if (clientConnection->bytesAvailable() < (int)sizeof(quint16))
return;
in >> blockSize;
}
/**********************************************************************************************/
if (clientConnection->bytesAvailable() < blockSize) //Wait until all the data are received
return;
QString messagefromclient;
in >> messagefromclient;
//Do something with the messagefronclient....
//Sending a file
QFile *file= new QFile("file.dat");
file->open(QIODevice::ReadOnly);
int filesize = file->size();
//We'll send the file in chunks of 64k (short of). We don't want to fill the memory at once if it's a large file
qint64 chunk = 64000;
qint64 filepos=0; //Position for reading/writing
while (filepos < filesize)
{
char *data = new char[chunk];
qint64 length = file->read(data, chunk);
clientConnection->write(data,length); //Send read data
filepos += length; //Go to new position depending what we read
delete [] data;
}
file->close();
delete file; //Free memory
/*QTcpSocket::disconnectFromHost() will close the connection after QTcpSocket has finished writing
the data to the network. Because QTcpSocket works asynchronously, the data will be written after
this function returns, and control goes back to Qt's event loop.
The socket will then close, which in turn will cause QObject::deleteLater() to delete it.*/
// clientConnection->disconnectFromHost();
}
void IP::serverStop()
{
tcpServer->close();
ui->iplabel->setText("Server closed");
delete tcpServer;
}
#include <QString>
#include <QFileDialog>
#include <QMessageBox>
#include <QTcpServer>
/***Server**************************************************************/
QTcpServer *tcpServer; // Server!
QTcpSocket *clientConnection; // Serverwise Socket for communication with the client
/***********************************************************************/
/*Server Slots************************/
void ServerRespond(); //Server response to connected clients
void sendFiles(); //Gets the requested file for uploading and sends it
/*************************************/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment