问题
I'm trying to send a file from client to server. But it sends only a part of file. Seems like it happens when the size of file is more than 2Mb. What can be the problem? Sorry if it's a stupid question but I can't find an answer in Google.
This is client cpp:
#include "widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent)
{
progressBar = new QProgressBar(this);
tcpSocket = new QTcpSocket(this);
fileLabel = new QLabel(this);
progressLabel = new QLabel(this);
fileBtn = new QPushButton(this);
fileBtn->setText("Open");
sendBtn = new QPushButton(this);
sendBtn->setText("Send");
layout = new QGridLayout;
layout->addWidget(fileBtn, 0, 0);
layout->addWidget(sendBtn, 0, 1);
layout->addWidget(fileLabel, 1, 0);
layout->addWidget(progressBar, 2, 0);
connect(fileBtn, &QPushButton::clicked, this, &Widget::fileOpened);
connect(sendBtn, &QPushButton::clicked, this, &Widget::onSend);
setLayout(layout);
}
Widget::~Widget()
{
}
void Widget::fileOpened()
{
fileName = QFileDialog::getOpenFileName(this, tr("Open file"));
QFileInfo fileInfo(fileName);
fileLabel->setText(fileInfo.fileName() + " : " + QString::number(fileInfo.size()));
qDebug() << fileName;
}
void Widget::onSend()
{
tcpSocket->connectToHost("127.0.0.1", 33333);
QFile file(fileName);
QDataStream out(tcpSocket);
int size = 0;
if (file.open(QIODevice::ReadOnly))
{
QFileInfo fileInfo(file);
QString fileName(fileInfo.fileName());
out << fileName;
qDebug() << fileName;
out << QString::number(fileInfo.size());
qDebug() << fileInfo.size();
progressBar->setMaximum(fileInfo.size());
while (!file.atEnd())
{
QByteArray rawFile;
rawFile = file.read(5000);
//false size inc
QFileInfo rawFileInfo(rawFile);
size += rawFileInfo.size();
out << rawFile;
progressBar->setValue(rawFile.size());
qDebug() << QString::number(fileInfo.size());
qDebug() << "ToSend:"<< rawFile.size();
}
out << "#END";
}
}
This is a server one:
#include "myserver.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
startBtn = new QPushButton(this);
startBtn->setText("Connect");
progressBar = new QProgressBar(this);
layout = new QGridLayout;
layout->addWidget(startBtn, 0, 0);
layout->addWidget(progressBar, 1, 0);
connect(startBtn, &QPushButton::clicked, this, &MainWindow::on_starting_clicked);
setCentralWidget (new QWidget (this));
centralWidget()->setLayout(layout);
}
MainWindow::~MainWindow()
{
server_status=0;
}
void MainWindow::on_starting_clicked()
{
startBtn->setText("Connecting...");
tcpServer = new QTcpServer(this);
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
if (!tcpServer->listen(QHostAddress::Any, 33333) && server_status==0)
{
qDebug() << QObject::tr("Unable to start the server: %1.").arg(tcpServer->errorString());
}
else
{
server_status=1;
qDebug() << QString::fromUtf8("Сервер запущен!");
startBtn->setText("Running");
}
}
void MainWindow::acceptConnection()
{
qDebug() << QString::fromUtf8("У нас новое соединение!");
tcpServerConnection = tcpServer->nextPendingConnection();
connect(tcpServerConnection,SIGNAL(readyRead()),this, SLOT(slotReadClient()));
// tcpServer->close();
QDir::setCurrent("/Users/vlad/Desktop/");
QString fileName;
QString fileSize;
}
void MainWindow::slotReadClient()
{
QDataStream in(tcpServerConnection);
QByteArray z;
if (!isInfoGot)
{
isInfoGot = true;
in >> fileName;
qDebug() << fileName;
in >> fileSize;
qDebug() << fileSize;
}
QFile loadedFile(fileName);
if (loadedFile.open(QIODevice::Append))
{
while (tcpServerConnection->bytesAvailable())
{
qDebug() << "bytesAvailable:" << tcpServerConnection->bytesAvailable();
in >> z;
qDebug() << z;
loadedFile.write(z);
}
loadedFile.close();
}
}
回答1:
Not so far i faced the same problem. So i find some solution. Test it on files about ~200Mb, no problems i see.
Sender part:
void FileSender::send()
{
QTcpSocket *socket = new QTcpSocket;
connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
// specified m_host and m_port to yours
socket->connectToHost(m_host, m_port);
socket->waitForConnected();
if ( (socket->state() != QAbstractSocket::ConnectedState) || (!m_file->open(QIODevice::ReadOnly)) ) {
qDebug() << "Socket can't connect or can't open file for transfer";
delete socket;
return;
}
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_4);
// This part i need to send not only file, but file name too
// Erase it if you needn't it
out << (quint32)0 << m_file->fileName();
QByteArray q = m_file->readAll();
block.append(q);
m_file->close();
out.device()->seek(0);
// This difference appear because of we send file name
out << (quint32)(block.size() - sizeof(quint32));
qint64 x = 0;
while (x < block.size()) {
qint64 y = socket->write(block);
x += y;
//qDebug() << x; // summary size you send, so you can check recieved and replied sizes
}
}
Server part:
I specified my server as :
class Server : public QTcpServer
{
Q_OBJECT
public:
explicit Server(QHostAddress host = QHostAddress::Any,
quint16 port = Constants::Server::DEFAULT_PORT,
QObject *parent = 0);
~Server();
public slots:
void start();
protected:
void incomingConnection(qintptr handle) Q_DECL_OVERRIDE;
private:
QHostAddress m_host;
quint16 m_port;
};
And realization:
Server::Server(QHostAddress host, quint16 port, QObject *parent)
: QTcpServer(parent),
m_host(host),
m_port(port)
{
...
// your settings init there
}
void Server::start()
{
if ( this->listen(m_host, m_port) )
qDebug() << "Server started at " << m_host.toString() << ":" << m_port;
else
qDebug() << "Can't start server";
}
void Server::incomingConnection(qintptr handle)
{
qDebug() << "incomingConnection = " << handle;
SocketThread *thread = new SocketThread(handle);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
As you can see i create new class SocketThread
for receiving as multitheading server i need.
class SocketThread : public QThread
{
Q_OBJECT
public:
SocketThread(qintptr descriptor, QObject *parent = 0);
~SocketThread();
protected:
void run() Q_DECL_OVERRIDE;
signals:
void onFinishRecieved();
private slots:
void onReadyRead();
void onDisconnected();
private:
qintptr m_socketDescriptor;
QTcpSocket *m_socket;
qint32 m_blockSize;
};
SocketThread::SocketThread(qintptr descriptor, QObject *parent)
: QThread(parent),
m_socketDescriptor(descriptor),
m_blockSize(0)
{
}
SocketThread::~SocketThread()
{
delete m_socket;
}
void SocketThread::run()
{
m_socket = new QTcpSocket;
m_socket->setSocketDescriptor(m_socketDescriptor);
connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()), Qt::DirectConnection);
connect(m_socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()), Qt::DirectConnection);
exec();
}
void SocketThread::onReadyRead()
{
QDataStream in(m_socket);
in.setVersion(QDataStream::Qt_5_4);
if (m_blockSize == 0) {
if (m_socket->bytesAvailable() < sizeof(quint32))
return;
in >> m_blockSize;
}
if (m_socket->bytesAvailable() < m_blockSize)
return;
QString fileName;
// get sending file name
in >> fileName;
QByteArray line = m_socket->readAll();
QString filePath = "YOUR"; // your file path for receiving
fileName = fileName.section("/", -1);
QFile target(filePath + "/" + fileName);
if (!target.open(QIODevice::WriteOnly)) {
qDebug() << "Can't open file for written";
return;
}
target.write(line);
target.close();
emit onFinishRecieved();
m_socket->disconnectFromHost();
}
void SocketThread::onDisconnected()
{
m_socket->close();
// leave event loop
quit();
}
I hope you will be able to adapt my code to your project. Best regards
回答2:
Vlad, I'd suggest you to look at a Qt Example, like this one: http://doc.qt.io/qt-5/qtbluetooth-btfiletransfer-example.html
Just ignore the BT specific stuff, and see what it do.
I think I can help you more if I had a stand-alone code, which I could compile... ie, you didn't posted the headers, main files, and so. Make a zip, up it somewhere, and I can try looking what is wrong with it when I come back from my late report delivery! =]
回答3:
I was looking for the same solution. In the end, I am able to transfer the file upto 635MB without QDataStream.
I simply used below code.
for the client.
void MyClient::establishConnection(QString ip, quint16 port){
this->ip = ip;
this->port = port;
socket = new QTcpSocket();
socket->connectToHost(ip, port);
socket->waitForConnected(3000);
QFile file("D:/dummy.txt"); //file path
file.open(QIODevice::ReadOnly);
QByteArray q = file.readAll();
socket->write(q);
}
for the server
void MyThread::readyRead(){
QByteArray line = socket->readAll();
QFile target;
target.setFileName("D:/new1.txt");
if (!target.open(QIODevice::WriteOnly | QIODevice::Append)) {
qDebug() << "Can't open file for written";
return;
}
target.write(line);
target.close();
qDebug() << "file size: " << target.size();
qDebug() << "Finished!";
}
Now, My Question is what will be the effect if I use QDataStream?
来源:https://stackoverflow.com/questions/30288385/how-to-send-a-file-in-qt