整站seo策略实施,婚庆网,网站建设业务的销售人员培训文档,vs c 网站开发Qt5开发及实例V2.0-第十八章-Qt-MyselfQQ实例 第18章-Qt MyselfQQ18.1 概述18.2 、发送文件18.3 、接收文件18.4 、保证传输的安全和稳定18.5 、总结 本章相关例程源码下载1.Qt5开发及实例_CH1801.rar 下载 第18章-Qt MyselfQQ 18.1 概述
MyselfQQ是一个基于Qt5框架开发的轻量… Qt5开发及实例V2.0-第十八章-Qt-MyselfQQ实例 第18章-Qt MyselfQQ18.1 概述18.2 、发送文件18.3 、接收文件18.4 、保证传输的安全和稳定18.5 、总结 本章相关例程源码下载1.Qt5开发及实例_CH1801.rar 下载 第18章-Qt MyselfQQ 18.1 概述
MyselfQQ是一个基于Qt5框架开发的轻量级即时通讯软件支持文本、图片、语音、文件等多种消息类型的发送和接收。其中文件传输是MyselfQQ的一个核心功能可以实现高效、稳定、安全的文件传输。
本文将介绍MyselfQQ的文件传输功能包括如何发送和接收文件以及如何保证传输的安全性和稳定性。同时本文会提供相关的代码示例以方便开发者进行参考和实践。 18.2 、发送文件
1.1 选择文件
要发送文件需要先选择要发送的文件。在MyselfQQ中可以通过打开本地文件夹或者拖拽文件到发送窗口来选择要发送的文件。
打开本地文件夹的方法比较简单只需要在主界面点击“文件”菜单选择“打开文件夹”然后在弹出的文件选择框中选择要发送的文件即可。
如果要通过拖拽文件来选择要发送的文件可以在主界面直接拖拽文件到发送窗口或者在本地文件夹中选择要发送的文件然后拖拽到发送窗口即可。
1.2 发送文件
选择好要发送的文件后就可以将文件发送给对方了。在MyselfQQ中发送文件的逻辑可以分为以下几个步骤
创建文件传输对象
在发送文件之前需要先创建文件传输对象。文件传输对象包含了发送方和接收方的相关信息以及要发送的文件的路径、大小等信息。
文件传输对象的定义如下
struct FileTransferObject
{QString fileName; // 文件名QString filePath; // 文件路径qint64 fileSize; // 文件大小QString senderName; // 发送方用户名QString receiverName; // 接收方用户名QString ip; // 接收方IP地址qint16 port; // 接收方端口号bool isAccepted; // 是否被接收bool isSending; // 是否正在发送bool isFinished; // 是否发送完成qint64 sentSize; // 已发送大小QTcpSocket* socket; // 用于发送数据的TCP连接
};其中senderName和receiverName分别表示发送方和接收方的用户名ip和port表示接收方的IP地址和端口号isAccepted、isSending和isFinished分别表示文件是否被接收、是否正在发送、是否发送完成sentSize表示已发送的文件大小socket表示用于发送数据的TCP连接。
获取接收方IP地址和端口号
在创建文件传输对象之后需要获取接收方的IP地址和端口号。这里使用UDP广播来实现即发送一个UDP广播让接收方返回自己的IP地址和端口号。
发送UDP广播的代码如下
void MainWindow::broadcast()
{QByteArray datagram hello;QHostAddress broadcastAddress QHostAddress::Broadcast;quint16 port 6666;udpSocket-writeDatagram(datagram, broadcastAddress, port);
}在发送UDP广播之后需要监听接收方返回的IP地址和端口号。当接收到回复消息时就可以获取到接收方的IP地址和端口号了。
void MainWindow::processPendingDatagrams()
{while (udpSocket-hasPendingDatagrams()){QByteArray datagram;datagram.resize(udpSocket-pendingDatagramSize());QHostAddress sender;quint16 senderPort;udpSocket-readDatagram(datagram.data(), datagram.size(), sender, senderPort);// 处理接收到的UDP数据包}
}处理接收到的UDP数据包的具体代码如下
void MainWindow::processBroadcastDatagram(const QByteArray datagram, const QHostAddress sender, quint16 senderPort)
{if (datagram hello){QByteArray response QString(%1,%2).arg(QHostInfo::localHostName()).arg(tcpServer-serverPort()).toUtf8();udpSocket-writeDatagram(response, sender, senderPort);}else if (datagram.startsWith(IP:)){QString receiverName datagram.mid(3);QString ip sender.toString();quint16 port senderPort;FileTransferObject* obj findFileTransferObject(receiverName);if (obj ! nullptr){obj-ip ip;obj-port port;// 开始发送文件startSendFile(obj);}}
}在处理接收到的UDP数据包时如果收到的是“hello”消息就会回复一个包含本机主机名和TCP监听端口号的消息。如果收到的是“IP:xxx”消息就会获取到接收方的IP地址和端口号并开始发送文件。
开始发送文件
在获取到接收方的IP地址和端口号后就可以开始发送文件了。文件的发送采用TCP连接来进行因为TCP连接可以保证传输的稳定性和安全性。
发送文件的关键代码如下
void MainWindow::startSendFile(FileTransferObject* obj)
{QTcpSocket* socket new QTcpSocket(this);obj-socket socket;connect(socket, SIGNAL(connected()), this, SLOT(onSendConnected()));connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)));connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSendError(QAbstractSocket::SocketError)));socket-connectToHost(obj-ip, obj-port);obj-isSending true;obj-isAccepted true;obj-sentSize 0;obj-isFinished false;
}void MainWindow::onSendConnected()
{QTcpSocket* socket qobject_castQTcpSocket*(sender());if (socket ! nullptr){FileTransferObject* obj findFileTransferObject(socket);if (obj ! nullptr){QFile file(obj-filePath);if (file.open(QIODevice::ReadOnly)){QByteArray block;QDataStream out(block, QIODevice::WriteOnly);out.setVersion(QDataStream::Qt_5_9);out qint64(0) qint64(0) obj-fileName;qint64 fileSize file.size();out fileSize;socket-write(block);obj-isAccepted true;obj-fileSize fileSize;}else{socket-close();}}}
}void MainWindow::onBytesWritten(qint64 bytes)
{QTcpSocket* socket qobject_castQTcpSocket*(sender());if (socket ! nullptr){FileTransferObject* obj findFileTransferObject(socket);if (obj ! nullptr){obj-sentSize bytes;if (obj-sentSize obj-fileSize){obj-isFinished true;socket-close();}else{// 继续发送剩余的数据}}}
}void MainWindow::onSendError(QAbstractSocket::SocketError error)
{QTcpSocket* socket qobject_castQTcpSocket*(sender());if (socket ! nullptr){FileTransferObject* obj findFileTransferObject(socket);if (obj ! nullptr){obj-isSending false;obj-isAccepted false;emit sendFileError(obj-fileName, obj-senderName, obj-receiverName, socket-errorString());// 关闭socket}}
}在开始发送文件时会创建一个QTcpSocket对象然后连接到接收方的IP地址和端口号。当连接成功后会发送一个包含文件名和文件大小的消息让接收方做好接收文件的准备。接着会按照一定的数据块大小将文件分块发送到接收方。每发送一个数据块都会记录已发送的文件大小以便在下次发送时从上次发送的位置开始继续发送。
在发送文件的过程中需要不断地检测已发送的文件大小是否等于文件总大小以判断是否已经发送完毕。如果已经发送完毕就会将isFinished设置为true然后关闭TCP连接。如果出现发送错误就会设置isSending为false将isAccepted设置为false并关闭TCP连接。
18.3 、接收文件
当MyselfQQ接收到文件传输请求时会弹出一个文件传输接收窗口用户可以选择接收或拒绝文件传输。
文件传输接收窗口的代码如下
void MainWindow::showFileTransferDialog(FileTransferObject* obj)
{FileTransferDialog* dialog new FileTransferDialog(obj, this);connect(dialog, SIGNAL(accepted(FileTransferObject*)), this, SLOT(onFileTransferAccepted(FileTransferObject*)));connect(dialog, SIGNAL(rejected(FileTransferObject*)), this, SLOT(onFileTransferRejected(FileTransferObject*)));dialog-show();
}如果用户选择接收文件就会开始接收文件。接收文件的过程采用TCP连接来完成与发送文件的过程类似。
接收文件的关键代码如下
void MainWindow::startReceiveFile(FileTransferObject* obj)
{QTcpSocket* socket new QTcpSocket(this);obj-socket socket;connect(socket, SIGNAL(connected()), this, SLOT(onReceiveConnected()));connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onReceiveError(QAbstractSocket::SocketError)));socket-connectToHost(obj-senderIp, obj-senderPort);obj-isSending false;obj-isAccepted true;obj-isFinished false;
}void MainWindow::onReceiveConnected()
{QTcpSocket* socket qobject_castQTcpSocket*(sender());if (socket ! nullptr){FileTransferObject* obj findFileTransferObject(socket);if (obj ! nullptr){QByteArray block;QDataStream in(block, QIODevice::ReadOnly);in.setVersion(QDataStream::Qt_5_9);qint64 blockSize qint64(0);qint64 fileSize qint64(0);QString fileName;socket-bytesAvailable();while (socket-bytesAvailable() sizeof(qint64) * 2 sizeof(QString)){if (!socket-waitForReadyRead(30000)){socket-close();return;}}in blockSize;in fileSize;in fileName;obj-isAccepted true;obj-fileSize fileSize;obj-fileName fileName;obj-sentSize 0;}}
}void MainWindow::onReadyRead()
{QTcpSocket* socket qobject_castQTcpSocket*(sender());if (socket ! nullptr){FileTransferObject* obj findFileTransferObject(socket);if (obj ! nullptr){if (obj-isFinished){return;}if (obj-sentSize 0){obj-file new QFile(obj-filePath);if (!obj-file-open(QIODevice::WriteOnly)){socket-close();return;}}qint64 bytesCount qint64(0);QByteArray buffer;while (socket-bytesAvailable() 0){buffer socket-read(qMin(socket-bytesAvailable(), qint64(1024)));bytesCount obj-file-write(buffer);obj-sentSize bytesCount;}if (obj-sentSize obj-fileSize){obj-isFinished true;obj-file-close();socket-close();emit receiveFileFinished(obj-fileName, obj-senderName, obj-receiverName);}}}
}void MainWindow::onReceiveError(QAbstractSocket::SocketError error)
{QTcpSocket* socket qobject_castQTcpSocket*(sender());if (socket ! nullptr){FileTransferObject* obj findFileTransferObject(socket);if (obj ! nullptr){obj-isSending false;obj-isAccepted false;emit receiveFileError(obj-fileName, obj-senderName, obj-receiverName, socket-errorString());// 关闭socket}}
}当接收方与发送方建立TCP连接后接收方会等待发送方发送一个消息其中包含了文件名和文件大小。接收方会先读取这个消息然后创建一个与文件名相同的文件并开始接收发送方发送的数据。每接收一段数据就会将其写入文件并记录已接收的文件大小。当已接收的文件大小等于文件总大小时就认为文件已经接收完成。
18.4 、保证传输的安全和稳定
在MyselfQQ中为了保证文件传输的安全和稳定采取了以下几个措施 采用TCP连接传输文件以保证传输的稳定性和安全性。 对文件进行分块传输每个数据块的大小为1024字节以减小传输过程中出现中断的风险。 在发送文件时会记录已发送的文件大小以便在下次发送时从上次发送的位置开始继续发送。 在接收文件时会记录已接收的文件大小以便在下次接收时从上次接收的位置开始继续接收。 在发送文件和接收文件时会对TCP连接的错误进行处理以保证传输的可靠性和稳定性。
18.5 、总结
MyselfQQ的文件传输功能采用TCP连接来实现支持多种类型的文件传输如文本、图片、语音和文件等。在文件传输过程中采取了多种措施来保证传输的安全性和稳定性。开发者可以根据本文提供的代码示例学习和实践以在自己的应用中实现类似的文件传输功能。 本章相关例程源码下载
1.Qt5开发及实例_CH1801.rar 下载
Qt5开发及实例_CH1801.rar