传输流程
利用Sokcet通信中TCP进行文件的传输,可以分为两个模块:分别是服务端以及客户端。
大致流程则是在服务端中发送相应的文件,客户端则负责接收。
具体如下:
先通过通信将服务端与客户端连接,在客户端中通过相应的ip地址以及设定的端口port去获取与服务端的连接。而在服务端监听到相应的客户端时,则可成功连接,完成通信。此时则可以通过相应路径选择相应的文件进行发送。而客户端可以通过接收到的文件信息,将之分为文件名以及文件大小等相应信息去创建一个相同的文件,从而实现文件的传输。
代码说明
在服务端中主要是选择文件和发送文件,具体如下说明:
先对服务端窗口进行布局。
this -> resize(300,300);
this -> move(900,400);
this -> setWindowTitle(QString::fromLocal8Bit("服务器"));
SendBtn = new QPushButton("sendfile",this);
ChooseBtn = new QPushButton("choosefile",this);
p_TextEdit = new QTextEdit(this);
QLabel *TextLabel = new QLabel(QString::fromLocal8Bit("服务器"), this);
QGridLayout *ServerLayout = new QGridLayout(this);
ServerLayout -> addWidget(SendBtn,4,0,1,1);
ServerLayout -> addWidget(ChooseBtn,4,3,1,1);
ServerLayout -> addWidget(p_TextEdit,1,0,1,4);
ServerLayout -> addWidget(TextLabel,0,2,1,1,Qt::AlignCenter);//设置服务端的布局
//将选择按钮设置成可点击,发送按钮不可点击。
SendBtn ->setEnabled(false);
ChooseBtn ->setEnabled(true);
p_TcpServer = new QTcpServer(this);
p_TcpSocket = new QTcpSocket(this);
p_TcpServer -> listen(QHostAddress::Any,8888);//监听客户端
connect(p_TcpServer,SIGNAL(newConnection()),this,SLOT(getConnect()));//连接成功则进入getConnect函数。
connect(&timer,SIGNAL(timeout()),this,SLOT(sendData()));//设置定时器信号与槽
connect(p_TcpSocket,SIGNAL(readyRead()),this,SLOT(readData()));
连接成功后则可以进行文件的选择,选择完成后就可以将文件发送。
void ServerWidget::getConnect()
{
p_TcpSocket = p_TcpServer -> nextPendingConnection();
QString ip = p_TcpSocket -> peerAddress().toString();
quint16 port = p_TcpSocket -> peerPort();
QString str = QString("[%1:%2] Connected").arg(ip).arg(port);
p_TextEdit -> setText(str);
connect(ChooseBtn,SIGNAL(clicked()),this,SLOT(chooseFile()));
}
void ServerWidget::chooseFile()
{
QString FilePath = QFileDialog::getOpenFileName(this,"open","C:/Users/MSI-NB/Desktop/test/");//获取文件的路径。
//打开文件
if(FilePath.isEmpty() == false)
{
fileName.clear();
fileSize = 0;
QFileInfo info(FilePath);
fileName = info.fileName();//获取文件名
fileSize = info.size();//获取文件大小
sendSize = 0;
//打开文件
file.setFileName(FilePath);
bool isOK = file.open(QIODevice::ReadOnly);
if(isOK == false)
{
qDebug()<< "open error!";
}
p_TextEdit -> append(FilePath);
SendBtn -> setEnabled(true);
ChooseBtn -> setEnabled(false);//文件选择完成后则将choose按钮设置成不可点击而send按钮为可点击
connect(SendBtn,SIGNAL(clicked()),this,SLOT(sendFile()));
}
else
{
qDebug()<< "filepath is error";
}
}
在点击了send按钮进行文件的发送后,则可以进入sendFile函数进行文件的发送:
在发送文件时有时会产生黏包情况,其形成原因有可能是因为发送文件的时间间隔相对较短,后面的信息会与前面的信息连在一起,影响对文件的阅读。而这种由于时间间隔较短而产生的黏包,则可以通过使用定时器来延长时间间隔,从而避免黏包。
void ServerWidget::sendFile()
{
//设置文件的头部信息。
QString head = QString("%1##%2").arg(fileName).arg(fileSize);
qint64 len = p_TcpSocket->write(head.toUtf8());
if(len > 0)
{
timer.start(20);//将定时器开启从而可以防止文件黏包。
}
else
{
qDebug()<<"send headfile error!";
file.close();
SendBtn -> setEnabled(false);
ChooseBtn -> setEnabled(true);
}
}
而在客户端中主要则是申请连接服务端并接收文件:
首先先是对客户端窗口进行布局。
ClientWidget::ClientWidget(QWidget *parent) : QWidget(parent)
{
this -> resize(300,300);
this -> move(550,400);
this -> setWindowTitle(QString::fromLocal8Bit("客户端"));
is_start =true;
connectBtn = new QPushButton("connect",this);
QLabel *ipLabel = new QLabel("ip:",this);
QLabel *portLabel = new QLabel("port:",this);
ipEdit = new QLineEdit("127.0.0.1",this);
portEdit = new QLineEdit("8888",this);
textEdit = new QTextEdit(this);
QGridLayout *ClientLayout = new QGridLayout(this);
ClientLayout -> addWidget(connectBtn,0,4,2,1,Qt::AlignCenter);
ClientLayout -> addWidget(ipLabel,1,0,1,1);
ClientLayout -> addWidget(portLabel,0,0,1,1);
ClientLayout -> addWidget(portEdit,0,1,1,3);
ClientLayout -> addWidget(ipEdit,1,1,1,3);
ClientLayout -> addWidget(textEdit,2,0,1,5);
textEdit -> setReadOnly(true);
p_TcpSocket = new QTcpSocket(this);
connect(connectBtn,SIGNAL(clicked()),this,SLOT(getConnect()));
connect(p_TcpSocket,SIGNAL(readyRead()),this,SLOT(recvData()));
}
在点击了connect按钮后进入getConnect函数连接服务器。
void ClientWidget::getConnect()
{
QString ip = ipEdit ->text();
quint16 port = portEdit -> text().toInt();
p_TcpSocket -> connectToHost(QHostAddress(ip),port);
}
当与服务端连接成功后,接收服务端发送来的文件:
void ClientWidget::recvData()
{
QByteArray buf = p_TcpSocket -> readAll();
//若是头部文件则获取文件名以及文件大小,并创建文件。
if(is_start == true)
{
is_start = false;
fileName = QString(buf).section("##",0,0);
fileSize = QString(buf).section("##",1,1).toInt();
recvSize = 0;
file.setFileName(fileName);
file.open(QIODevice::WriteOnly);
//不是头部文件则直接读取其内部信息。
else
{
qint64 len = file.write(buf);
recvSize += len ;
//当接收到数据的大小与文件大小相等时则关闭文件并弹窗说明。
if(recvSize == fileSize)
{
file.close();
QMessageBox::information(this,"Success","Success!!!!");
textEdit -> setText("success!");
p_TcpSocket -> disconnectFromHost();
p_TcpSocket -> close();
}
}
}
版权声明:本文为weixin_38516302原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。