Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Sending multiple files with a for Loop and QTcpSocket



  • Hello Everyone,

    i'm trying to send multiple files from a Client to a Server with QTcpSocket. In the chosen Directory I loop over the Files there and write them one after one in the socket. Here's the Code to the Client:

    Client::Client(QObject *parent) :
    	QObject(parent)
    {
    }
    
    void Client::Connected()
    {
    	//Creating the Socket Object
    	QTcpSocket *socket = new QTcpSocket;
    	//Setting the IP Adress to the Target System. Will  later be set through User Input
    	QString  HostAdress = "192.168.10.10";
    	printf(QString("Connection to Host under started\n").toStdString().c_str());
    	//Connecting to the Server
    	socket->connectToHost(HostAdress, 1234);
    	if (!socket->waitForConnected())
    	{
    		printf("Connection Failed \n");
    	}
    	else
    	{
    printf(QString("Connected successfully\n").toStdString().c_str());
    QDir ProjectPath("C:\\Users\\X240\\Desktop\\Masterarbeit\\ZF-Schulungssystem\\ZF-Schulungssystem\\TwinCAT\\");
    int count = 0;
    QStringList fileNameList = ProjectPath.entryList(QDir::Files); //Considering only the files 
    for (int i =0; i <fileNameList.size(); i++)
      {	
          QString ZFsolutionName = fileNameList.at(i);
          printf(QString("The File name is " + ZFsolutionName +"\n").toStdString().c_str());
          QString Path;
          Path = ProjectPath.absoluteFilePath(ZFsolutionName);
          printf(QString("" + Path + "\n").toStdString().c_str());
         QFile TCFile  (Path); //Opening the Local File that will be sent
        if (!TCFile.exists())
    	{
    	printf(QString(ZFsolutionName + " does not exist\n").toStdString().c_str());
    	}
        else
    	{
    	printf(QString(ZFsolutionName + " file exists. Opening...\n").toStdString().c_str());
    	if (!TCFile.open(QIODevice::ReadOnly))
    	{
    	printf("could not open File");
    	}
            else
    	{
    	printf("File opened!");
    	QByteArray block;
            QByteArray	q = TCFile.readAll(); 
    	block.append(q);				 
    	socket->write(q);
            int Size = q.size();
    	std::cout << "The Size of the Data is " << Size << endl;
    
    			}
    		}
    	}
    

    Now the Server

    Server::Server(QObject *parent) :
    	QTcpServer(parent)
    {
    }
    void Server::start()
    {
    	QHostAddress pHost;
    	quint16 port;
    	port = 2323;
    	QString printAddress;
    	pHost.setAddress("192.168.10.10");
    	printAddress = pHost.toString();
    	QString Port; 
    	Port = QString::number(port);
    
    	if (this->listen(pHost, 1234))
    	{
    	printf(QString("Server started at  and Listening ").toStdString().c_str());
    	}
    	else
    	{
    		printf("Server could not be started \n");
    	}
    }
    void Server::incomingConnection(qintptr m_socketDescriptor)
    {
    	printf("incoming Connection \n");
    	SocketThread *thread = new SocketThread(m_socketDescriptor, this);
    	connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    	thread->start(); //this jumps directly to the run function in the socket thread. 
    }
    
    

    And here's the Code to the Thread

    SocketThread::SocketThread(qintptr descriptor, QObject *parent) :
    	QThread(parent)
    {m_socketDescriptor = descriptor;}
    
    void SocketThread::run()
    {
    	m_socket = new QTcpSocket;
    	if (!m_socket->setSocketDescriptor(this->m_socketDescriptor))
    	{
    		printf("Error");
    		return;
    	}
    connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()), Qt::DirectConnection);
    connect(m_socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()), Qt::DirectConnection);
    printf("Thread started because Client connected \n");
    
    qDebug() << m_socketDescriptor << "Client Connected \n";
    exec(); 
    }
    
    void SocketThread::onReadyRead()
    {
    QString fileName;  
    fileName = "TwinCAT_Virtuos_Testprojekt_VirtuosIOWizard@1.sln";
    QByteArray line = m_socket->readAll(); 
    QString FilePath = "C:\\test"; // hier the Path on the receiving End
    QFile target(FilePath + "/" + fileName);
    if (!target.open(QIODevice::WriteOnly)) { 
    
    printf("can't open File for writing");
    }
    else
    {	target.write(line); //Writing the byte Array line to the target file 
    	printf("File received");
    	target.close();
    }
    emit onFinishRecieved();
    m_socket->disconnectFromHost();
    }
    
    void SocketThread::onDisconnected()
    {
    	m_socket->deleteLater();
    	exit(0);
    }
    

    With the Code above I'm able only to send the first file in the Loop.. All other Files in the Directory are not sent although they get looped over. What am I doing wrong? Do I have to disconnect from the Host and connect again each time??

    Thanks !



  • @JohnSRV
    I'm not going to answer about whatever you say is your issue. [EDIT See end of post.]

    Instead I'm going to say: so far as I can see, you just send the contents of each file in a loop one after the other, period.

    This is not right. The receiver (server) will never know where one file ends and the next begins. It will just see a constant stream of bytes.

    You have to invent a protocol that your client & server agree on, for how to start & end a file transfer. For example, you might say that the first n-bytes describe the length of the file to follow. Whatever, there has to be such a thing.

    You could even use disconnect to mark the end of each of file, though that would not be my choice. You could also have a main port connected like now, and then use a second port for the file transfer, which is what FTP does.

    But whatever, you need to think this through before you will get anywhere.

    [EDIT Actually, after re-reading your "All other Files in the Directory are not sent although they get looped over." I think this may be what your issue is anyway! If you look, don't you find your file at the server at the end contains the contents of all three files sent, one after the other?]



  • @JonB Thanks for your answer! It made me aware of how a Data Stream actually works.
    The File received by the the Server has the size of the last file in the Directory which is 33 ko. The Data of the files before gets overwritten somehow.

    I tried to implement a way to mark the end of a file using its size.

    for (int i = 0; i < fileNameList.size(); i++)
    {
    QString ZFsolutionName = fileNameList.at(i);
    printf(QString("The File name is " + ZFsolutionName + "\n").toStdString().c_str());
    QString Path;
    Path = ProjectPath.absoluteFilePath(ZFsolutionName);
    printf(QString("" + Path + "\n").toStdString().c_str());
    QFile TCFile(Path); //Opening the Local File that will be sent
    if (!TCFile.exists())
    	{
    		printf(QString(ZFsolutionName + " does not exist\n").toStdString().c_str());
    	}
    else
    	{
    	printf(QString(ZFsolutionName + " file exists. Opening...\n").toStdString().c_str());
    	if (!TCFile.open(QIODevice::ReadOnly))
    	{
           printf("could not open File");
    	}
    	else
    	{
    	printf("File opened!");
    	qint64 Size = TCFile.size();
    	QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly); /.
    QByteArray	q = TCFile.readAll(); 
    block.append(q);				
    TCFile.close();
    out.device()->seek(0);
    qint64 x = 0;
    while (x < Size)
    {
     qint64 y = socket->write(q);
     x += y;
    }
    std::cout << "The Size of the Data is " << Size << endl;
    
    }
    }
    

    Now I'm getting a file with a size of 5 ko on the Server side which doesn't match the size of any of the files in the directory.


Log in to reply