引言
客户端与服务器之间的数据传送在很多案例场景里都会有应用。这里Jungle用Qt来简单设计实现一个场景,即:
①两端:服务器QtServer和客户端QtClient
②功能:服务端连接客户端,两者能够互相发送消息,传送文件,并且显示文件传送进度。
环境:VS2008 Qt4.8.6 Qt设计
本文紧接着上一篇文章
04
客户端实现
代码语言:javascript复制void QtClient::sendFile()
{
this->localFile = new QFile(filename);
if(!localFile->open(QFile::ReadOnly))
{
ui.textEdit->append(tr("Client:open file error!"));
return;
}
///获取文件大小
this->totalBytes = localFile->size();
QDataStream sendout(&outBlock,QIODevice::WriteOnly);
sendout.setVersion(QDataStream::Qt_4_8);
QString currentFileName = filename.right(filename.size()-filename.lastIndexOf('/')-1);
qDebug()<<sizeof(currentFileName);
////保留总代大小信息空间、文件名大小信息空间、文件名
sendout<<qint64(0)<<qint64(0)<<currentFileName;
totalBytes = outBlock.size();
sendout.device()->seek(0);
sendout<<totalBytes<<qint64((outBlock.size()-sizeof(qint64)*2));
bytestoWrite = totalBytes-fileSocket->write(outBlock);
outBlock.resize(0);
}
这里同样说明两点:
①setVision():设定数据序列的版本,官方文档里说明这个不是必须的,但是推荐我们要去进行这一步的工作。我这里是Qt4.8.6,所以设定为Qt4.8.见下图(截自Qt官方文档)
②qint64:这个类型在Jungle之前的博客里也提到过,是指qt的无符号的整型,64位
代码语言:javascript复制void QtClient::updateFileProgress(qint64 numBytes)
{
////已经发送的数据大小
bytesWritten = (int)numBytes;
////如果已经发送了数据
if(bytestoWrite > 0)
{
outBlock = localFile->read(qMin(bytestoWrite,perDataSize));
///发送完一次数据后还剩余数据的大小
bytestoWrite -= ((int)fileSocket->write(outBlock));
///清空发送缓冲区
outBlock.resize(0);
}
else
localFile->close();
////更新进度条
this->ui.progressBar->setMaximum(totalBytes);
this->ui.progressBar->setValue(bytesWritten);
////如果发送完毕
if(bytesWritten == totalBytes)
{
localFile->close();
//fileSocket->close();
}
}
void QtClient::updateFileProgress()
{
QDataStream inFile(this->fileSocket);
inFile.setVersion(QDataStream::Qt_4_8);
///如果接收到的数据小于16个字节,保存到来的文件头结构
if(bytesReceived <= sizeof(qint64)*2)
{
if((fileSocket->bytesAvailable()>=(sizeof(qint64))*2) && (filenameSize==0))
{
inFile>>totalBytes>>filenameSize;
bytesReceived = sizeof(qint64)*2;
}
if((fileSocket->bytesAvailable()>=filenameSize) && (filenameSize != 0))
{
inFile>>filename;
bytesReceived = filenameSize;
filename = "ServerData/" filename;
localFile = new QFile(filename);
if(!localFile->open(QFile::WriteOnly))
{
qDebug()<<"Server::open file error!";
return;
}
}
else
return;
}
/////如果接收的数据小于总数据,则写入文件
if(bytesReceived < totalBytes)
{
bytesReceived = fileSocket->bytesAvailable();
inBlock = fileSocket->readAll();
localFile->write(inBlock);
inBlock.resize(0);
}
////数据接收完成时
if(bytesReceived == totalBytes)
{
this->ui.textEdit->append("Receive file successfully!");
bytesReceived = 0;
totalBytes = 0;
filenameSize = 0;
localFile->close();
//fileSocket->close();
}
}
05
服务端实现
类的设计:
代码语言:javascript复制class QtServer : public QWidget
{
Q_OBJECT
public:
QtServer(QWidget *parent = 0, Qt::WFlags flags = 0);
~QtServer();
QTcpServer *server;
QTcpSocket *socket;
QTcpServer *fileserver;
QTcpSocket *filesocket;
private slots:
void sendMessage();
void acceptConnection();
////接收客户端发送的数据
void receiveData();
void acceptFileConnection();
void updateFileProgress();
void displayError(QAbstractSocket::SocketError socketError);
///选择发送的文件
void selectFile();
void sendFile();
////更新文件传送进度
void updateFileProgress(qint64);
private:
Ui::QtServerClass ui;
////传送文件相关变量
qint64 totalBytes;
qint64 bytesReceived;
qint64 bytestoWrite;
qint64 bytesWritten;
qint64 filenameSize;
QString filename;
///每次发送数据大小
qint64 perDataSize;
QFile *localFile;
////本地缓冲区
QByteArray inBlock;
QByteArray outBlock;
////系统时间
QDateTime current_date_time;
QString str_date_time;
};
实现:
代码语言:javascript复制#include "qtserver.h"
#include <QDataStream>
#include <QMessageBox>
#include <QString>
#include <QByteArray>
QtServer::QtServer(QWidget *parent, Qt::WFlags flags)
: QWidget(parent, flags)
{
ui.setupUi(this);
this->socket = new QTcpSocket(this);
this->server = new QTcpServer(this);
///开启监听
this->server->listen(QHostAddress::Any,6666);
connect(this->server,SIGNAL(newConnection()),this,SLOT(acceptConnection()));
connect(ui.pushButton_send,SIGNAL(clicked()),this,SLOT(sendMessage()));
///文件传送套接字
this->filesocket = new QTcpSocket(this);
this->fileserver = new QTcpServer(this);
this->fileserver->listen(QHostAddress::Any,8888);
connect(this->fileserver,SIGNAL(newConnection()),this,SLOT(acceptFileConnection()));
//// 文件传送相关变量初始化
bytesReceived = 0;
totalBytes = 0;
filenameSize = 0;
connect(ui.pushButton_selectFile,SIGNAL(clicked()),this,SLOT(selectFile()));
connect(ui.pushButton_sendFile,SIGNAL(clicked()),this,SLOT(sendFile()));
}
QtServer::~QtServer()
{
}
void QtServer::acceptConnection()
{
////返回一个socket连接
this->socket = this->server->nextPendingConnection();
connect(socket,SIGNAL(readyRead()),this,SLOT(receiveData()));
}
void QtServer::acceptFileConnection()
{
bytesWritten = 0;
///每次发送数据大小为64kb
perDataSize = 64*1024;
this->filesocket = this->fileserver->nextPendingConnection();
///接受文件
connect(filesocket,SIGNAL(readyRead()),this,SLOT(updateFileProgress()));
connect(filesocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(updateFileProgress(qint64)));
connect(filesocket,SIGNAL(bytesWritten(qint64)),this,SLOT(displayError(QAbstractSocket::SocketError socketError)));
}
void QtServer::sendMessage()
{
this->socket->write(ui.lineEdit->text().toLatin1());
////显示
current_date_time = QDateTime::currentDateTime();
str_date_time = current_date_time.toString("yyyy-MM-dd hh:mm:ss");
QString str = "You " str_date_time "n" ui.lineEdit->text();
ui.browser->append(str);
}
void QtServer::receiveData()
{
/////获取当前时间
current_date_time = QDateTime::currentDateTime();
str_date_time = current_date_time.toString("yyyy-MM-dd hh:mm:ss") "n";
////接收数据
QString str = this->socket->readAll();
////显示
str = "Client " str_date_time str;
this->ui.browser->append(str);
}
void QtServer::updateFileProgress()
{
QDataStream inFile(this->filesocket);
inFile.setVersion(QDataStream::Qt_4_8);
///如果接收到的数据小于16个字节,保存到来的文件头结构
if(bytesReceived <= sizeof(qint64)*2)
{
if((filesocket->bytesAvailable()>=(sizeof(qint64))*2) && (filenameSize==0))
{
inFile>>totalBytes>>filenameSize;
bytesReceived = sizeof(qint64)*2;
}
if((filesocket->bytesAvailable()>=filenameSize) && (filenameSize != 0))
{
inFile>>filename;
bytesReceived = filenameSize;
////接收的文件放在指定目录下
filename = "ClientData/" filename;
localFile = new QFile(filename);
if(!localFile->open(QFile::WriteOnly))
{
qDebug()<<"Server::open file error!";
return;
}
}
else
return;
}
/////如果接收的数据小于总数据,则写入文件
if(bytesReceived < totalBytes)
{
bytesReceived = filesocket->bytesAvailable();
inBlock = filesocket->readAll();
localFile->write(inBlock);
inBlock.resize(0);
}
////更新进度条显示
this->ui.progressBar_fileProgress->setMaximum(totalBytes);
this->ui.progressBar_fileProgress->setValue(bytesReceived);
////数据接收完成时
if(bytesReceived == totalBytes)
{
this->ui.browser->append("Receive file successfully!");
bytesReceived = 0;
totalBytes = 0;
filenameSize = 0;
localFile->close();
//filesocket->close();
}
}
void QtServer::displayError(QAbstractSocket::SocketError socketError)
{
qDebug()<<socket->errorString();
socket->close();
}
void QtServer::selectFile()
{
filesocket->open(QIODevice::WriteOnly);
////文件传送进度更新
connect(filesocket,SIGNAL(bytesWritten(qint64)),this,SLOT(updateFileProgress(qint64)));
this->filename = QFileDialog::getOpenFileName(this,"Open a file","/","files (*)");
ui.lineEdit_fileName->setText(filename);
}
void QtServer::sendFile()
{
this->localFile = new QFile(filename);
if(!localFile->open(QFile::ReadOnly))
{
return;
}
///获取文件大小
this->totalBytes = localFile->size();
QDataStream sendout(&outBlock,QIODevice::WriteOnly);
sendout.setVersion(QDataStream::Qt_4_8);
QString currentFileName = filename.right(filename.size()-filename.lastIndexOf('/')-1);
////保留总代大小信息空间、文件名大小信息空间、文件名
sendout<<qint64(0)<<qint64(0)<<currentFileName;
totalBytes = outBlock.size();
sendout.device()->seek(0);
sendout<<totalBytes<<qint64((outBlock.size()-sizeof(qint64)*2));
bytestoWrite = totalBytes-filesocket->write(outBlock);
outBlock.resize(0);
}
void QtServer::updateFileProgress(qint64 numBytes)
{
////已经发送的数据大小
bytesWritten = (int)numBytes;
////如果已经发送了数据
if(bytestoWrite > 0)
{
outBlock = localFile->read(qMin(bytestoWrite,perDataSize));
///发送完一次数据后还剩余数据的大小
bytestoWrite -= ((int)filesocket->write(outBlock));
///清空发送缓冲区
outBlock.resize(0);
}
else
localFile->close();
////如果发送完毕
if(bytesWritten == totalBytes)
{
localFile->close();
//filesocket->close();
}
}
06
测试
http://mpvideo.qpic.cn/0af2c3lezq3veayob4aqobqbayff5wfdoctfyeyrbaga4danbada.f10002.mp4?