您的位置:首页 > 编程语言 > Qt开发

QT学习点滴记录(五)

2014-09-22 14:50 447 查看

QT 网络 TCP(二) 文件传输

一、服务端

1. 新建一个QT Gui Application, 命名为“TCPReceive”, 并修改pro文件(QT += network)2. 添加所需控件, 如下图所示其中“服务器端”Label的objectName为ServerStatusLabel;进度条Progress Bar的objectName为ServerProgressBar,设置其value属性为0;“开始监听”按钮的objectName为ListenPushButton3. 修改Widget.h文件(1) 添加头文件:#include <QtNetWork>(2)添加私有变量:
Ui::Widget *ui;
QTcpServer m_TcpServer;
QTcpSocket* m_pTcpServerConnection;
qint64 m_nTotalBytes;//存放总大小信息
qint64 m_nBytesReceived;//已收到数据的大小
qint64 m_nFileNameSize;//文件名的大小信息
QString m_strFileName;//存放文件名
QFile* m_pLocalFile;//本地文件
QByteArray m_inBlock;//数据缓冲区
(3)添加槽函数
private slots:
void Listen();
void AcceptConnection();
void UpdateServerProgress();
void DiaplayError(QAbstractSocket::SocketError);
void on_ListenPushButton_clicked();
4.修改Widget.cpp文件
(1)在构造函数添加如下代码:
m_nTotalBytes = 0;
m_nBytesReceived = 0;
m_nFileNameSize = 0;
connect(&m_TcpServer, SIGNAL(newConnection()), this,SLOT(AcceptConnection()));
(2)实现槽函数
void Widget::Listen()
{
ui->ListenPushButton->setEnabled(false);
m_nBytesReceived = 0;
if(!m_TcpServer.listen(QHostAddress::LocalHost, 6666))
{
qDebug() << m_TcpServer.errorString();
close();
return ;
}
ui->ServerStatusLabel->setText(tr("监听"));
}
void Widget::AcceptConnection()
{
m_pTcpServerConnection = m_TcpServer.nextPendingConnection();
connect(m_pTcpServerConnection, SIGNAL(readyRead()), this,
SLOT(UpdateServerProgress()));
connect(m_pTcpServerConnection, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(DiaplayError(QAbstractSocket::SocketError)));
ui->ServerStatusLabel->setText(tr("接受连接"));
m_TcpServer.close();
}
void Widget::UpdateServerProgress()
{
QDataStream in(m_pTcpServerConnection);
in.setVersion(QDataStream::Qt_4_8);
if(m_nBytesReceived <= sizeof(qint64) * 2)
{
if(m_pTcpServerConnection->bytesAvailable() >= sizeof(qint64) * 2 && m_nFileNameSize == 0)
{
in >> m_nTotalBytes >> m_nFileNameSize;
m_nBytesReceived += sizeof(qint64) * 2;
}
if(m_pTcpServerConnection->bytesAvailable() >= m_nFileNameSize && m_nFileNameSize != 0)
{
in >> m_strFileName;
ui->ServerStatusLabel->setText(tr("接收文件 %1 ...").arg(m_strFileName));
m_nBytesReceived += m_nFileNameSize;
m_pLocalFile = new QFile(m_strFileName);
if(!m_pLocalFile->open(QFile::WriteOnly))
{
qDebug() << "Open File Error!";
return ;
}
}
else
{
    return ;
}
}
if(m_nBytesReceived < m_nTotalBytes)
{
m_nBytesReceived += m_pTcpServerConnection->bytesAvailable();
m_inBlock = m_pTcpServerConnection->readAll();
m_pLocalFile->write(m_inBlock);
m_inBlock.resize(0);
}
ui->ServerProgressBar->setMaximum(m_nTotalBytes);
ui->ServerProgressBar->setValue(m_nBytesReceived);
if(m_nBytesReceived == m_nTotalBytes)
{
m_pTcpServerConnection->close();
m_pLocalFile->close();
ui->ListenPushButton->setEnabled(true);
ui->ServerStatusLabel->setText(tr("接收文件 %1 成功! ").arg(m_strFileName));
}
}
void Widget::DiaplayError(QAbstractSocket::SocketError)
{
qDebug() << m_pTcpServerConnection->errorString();
m_pTcpServerConnection->close();
ui->ServerProgressBar->reset();
ui->ServerStatusLabel->setText(tr("服务端就绪"));
ui->ListenPushButton->setEnabled(true);
}
void Widget::on_ListenPushButton_clicked()
{
Listen();
}
5. 为了可以显示中文信息, 在main.cpp中添加如下代码:
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
6.编译运行, 效果如下图

二、客户端

1. 新建QT Gui Application程序, 命名为TCPSender, 并修改pro文件(添加代码:QT += network)
2. 在ui文件中添加所需控件, 示意图如下:其中“主机”的Line Edit的objectName为HostLineEdit;“端口”后的Line Edit的objectName为PortLineEdit;下面的Progress Bar的objectName为ClientProgressBar,其value属性设为0;“状态”Label的objetName为ClientStatusLabel;“打开”按钮的objectName为openButton;“发送”按钮的objectName为SendPushButton3. 修改Widget.h文件(1)添加头文件:#include <QtNetWork>(2)添加私有变量:
QTcpSocket* m_pTcpClient;
QFile* m_pLocalFile;//要发送的文件
qint64 m_nTotalBytes;//数据总大小
qint64 m_nBytesWritten;//已经发送数据大小
qint64 m_nBytesToWrite;//剩余数据大小
qint64 m_nLoadSize;//每次发送数据的大小
QString m_strFileName;//保存文件路径
QByteArray m_OutBlock;//数据缓冲区, 即存放每次要发送的数据
(3)添加槽函数:
private slots:
void Send();    //连接服务器
void StartTransfer();   //发送文件大小等信息
void UpdateClientProgress(qint64);  //发送数据, 更新进度条
void DiaplayError(QAbstractSocket::SocketError);    //显示错误
void OpenFile();    //打开文件
void on_OpenPushButton_clicked();
void on_SendPushButton_clicked();
4.修改Widget.cpp文件
(1)在构造函数中添加如下代码:
m_nLoadSize = 4 * 1024;
m_nTotalBytes = 0;
m_nBytesWritten = 0;
m_nBytesToWrite = 0;
m_pTcpClient = new QTcpSocket(this);
//当连接服务器成功时, 发出connected信号, 开始传送文件
connect(m_pTcpClient, SIGNAL(connected()), this,SLOT(StartTransfer()));
//当有数据发送成功时, 更新进度条
connect(m_pTcpClient, SIGNAL(bytesWritten(qint64)), this,SLOT(UpdateClientProgress(qint64)));
connect(m_pTcpClient, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(DiaplayError(QAbstractSocket::SocketError)));
//设置“发送”按钮不可用
ui->SendPushButton->setEnabled(false);
(2)实现槽函数
void Widget::OpenFile()
{
m_strFileName = QFileDialog::getOpenFileName(this);
if(!m_strFileName.isEmpty())
{
ui->SendPushButton->setEnabled(true);
ui->ClientStatusLabel->setText(tr("打开文件 %1 成功!").arg(m_strFileName));
}
}
void Widget::Send()
{
//设置发送按钮不可用
ui->SendPushButton->setEnabled(false);
//初始化已发送字节为0
m_nBytesWritten = 0;
ui->ClientStatusLabel->setText(tr("连接中..."));
m_pTcpClient->connectToHost(ui->HostLineEdit->text(), ui->PortLineEdit->text().toInt());
}
void Widget::StartTransfer()
{
m_pLocalFile = new QFile(m_strFileName);
if(!m_pLocalFile->open(QFile::ReadOnly))
{
qDebug() << "Open File Error!";
return ;
}
m_nTotalBytes = m_pLocalFile->size();
QDataStream sendOut(&m_OutBlock, QIODevice::WriteOnly);
sendOut.setVersion(QDataStream::Qt_4_8);
QString currentFileName = m_strFileName.right(m_strFileName.size() - m_strFileName.lastIndexOf('/') - 1);
//依次写入总大小信息空间, 文件名大小信息空间, 文件名
sendOut << qint64(0) << qint64(0) << currentFileName;
//这里的总大小是文件名大小等信息和实际文件大小的总和
m_nTotalBytes += m_OutBlock.size();
sendOut.device()->seek(0);
//返回m_OutBlock的开始, 用实际的大小信息代替两个qint64(0)空间
sendOut << m_nTotalBytes << qint64(m_OutBlock.size() - sizeof(qint64) * 2);
//发送完头数据后剩余数据的大小
m_nBytesToWrite = m_nTotalBytes - m_pTcpClient->write(m_OutBlock);
ui->ClientStatusLabel->setText(tr("已连接"));
m_OutBlock.resize(0);
}
void Widget::UpdateClientProgress(qint64 numBytes)
{
//已经发送数据的大小
m_nBytesWritten += (int)numBytes;
//如果已经发送了数据
if(m_nBytesToWrite > 0)
{
//每次发送m_nLoadSize大小的数据, 这里设置为4KB, 如果剩余的数据不足, 就发送剩余数据的大小
m_OutBlock = m_pLocalFile->read(qMin(m_nBytesToWrite, m_nLoadSize));
//发送完一次数据后剩余数据的大小
m_nBytesToWrite -= (int)m_pTcpClient->write(m_OutBlock);
//清空发送缓冲区
    m_OutBlock.resize(0);
}
else    //如果没有发送任何数据, 则关闭文件
{
m_pLocalFile->close();
}
//更新进度条
ui->ClientProgressBar->setMaximum(m_nTotalBytes);
ui->ClientProgressBar->setValue(m_nBytesWritten);
//发送完毕
if(m_nBytesWritten == m_nTotalBytes)
{
ui->ClientStatusLabel->setText(tr("传送文件 %1 成功").arg(m_strFileName));
m_pLocalFile->close();
m_pTcpClient->close();
}
}
void Widget::DiaplayError(QAbstractSocket::SocketError)
{
qDebug() << m_pTcpClient->errorString();
m_pTcpClient->close();
ui->ClientProgressBar->reset();
ui->ClientStatusLabel->setText(tr("客户端准备就绪"));
ui->SendPushButton->setEnabled(true);
}
void Widget::on_OpenPushButton_clicked()
{
OpenFile();
}
void Widget::on_SendPushButton_clicked()
{
Send();
}
5.为了可以显示中文信息, 在main.cpp中添加如下代码:
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
6. 编译运行, 效果图如下:
7. 运行服务端, 然后点击监听按钮, 点击客户端中打开按钮, 选择本地文件, 进行传输, 示意图如下
                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: