与UDP协议单次传输数据大小要小于64KB不同,TCP协议利用套接字传输数据对数据大小没有限制,而且TCP协议的传输是可靠的,不会丢包,但是相应的传输速率会慢与UDP。
编程使用的是TCP SOCKET套接字。项目文件用百度网盘分享:
链接:https://pan.baidu.com/s/1kkDPIsK4jBxM1_m9iGs05Q
提取码:1234
1. 客户端UI
有几点注意事项:
1.客户端如果要传输文件到服务器端,需要指明服务器端的IP和Port。
2.connect:在填入服务器IP和Port后,按下此按钮进行服务端和客户端的连接。
3.进度条:表示传输进度。
2.服务器UI
3.客户端代码
#include "client.h"
#include "ui_client.h"
#include<QDebug>
#include<QMessageBox>//信息对话框
client::client(QWidget *parent) :
QWidget(parent),
ui(new Ui::client)
{
ui->setupUi(this);
tcpsocket = new QTcpSocket(this);
isstart = true;//发送文件信息/文件 标志:1/0
// 进度条初始值为0
ui->progressBar->setValue(0);
connect(tcpsocket,&QTcpSocket::readyRead,[=]()
{
//arry存储接收到的文件信息
QByteArray arry = tcpsocket->readAll();
if(true == isstart)
{
isstart = false;
//1、收到的是文件信息
//拆包:文件名##大小。拆包函数:section
fileName = QString(arry).section("##",0,0);
fileSize = QString(arry).section("##",1,1).toInt();
//接收到的文件大小=0
receiveSize = 0;
qint64 len = 0;
//创建文件设置为只写
file.setFileName(fileName);
bool isOK = file.open(QIODevice::WriteOnly);//isOK:文件成功打开标志
if(false == isOK)
{
qDebug()<<"文件打开失败";
tcpsocket->disconnectFromHost();
tcpsocket->close();
}
//初始化进度条
ui->progressBar->setMinimum(0);
ui->progressBar->setMaximum(fileSize/1024);
ui->progressBar->setValue(0);
}
else
{
//2、收到是文件内容
//arry存储的是接收到的文件信息,len:读取文件内容的大小
qint64 len = file.write(arry);
receiveSize += len;//累计已读文件大小
//更新进度条
ui->progressBar->setValue(receiveSize/1024);
qDebug()<<"receivesizr = "<<receiveSize<<" filesize="<<fileSize;
if(receiveSize == fileSize)//文件全部接收完
{
QMessageBox::information(this,"完成","文件已全部接收");
//tcpsocket->write("file done");
file.close();
tcpsocket->disconnectFromHost();
tcpsocket->close();
}
}
});
}
client::~client()
{
delete ui;
}
//connect按钮槽
void client::on_pushButtoncConnect_clicked()
{
//获取服务器IP Port
QString ip = ui->lineEditIP->text();
quint16 port = ui->lineEditPort->text().toInt();
tcpsocket->connectToHost(ip,port);//请求连接
}
4.服务器端代码
#include "server.h"
#include "ui_server.h"
#include<QFileDialog>//文本对话框
#include<QFile>
#include<QFileInfo>//获取文件信息
#include<QDebug>
#include<QMessageBox>//发送文件成功进行提示
server::server(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::server)
{
ui->setupUi(this);
tcpServer = new QTcpServer(this);
tcpServer->listen(QHostAddress::Any,7777);//服务器port:7777
connect(tcpServer,&QTcpServer::newConnection,[=](){
tcpSocket = tcpServer->nextPendingConnection();
//以下操作目的:在edit显示申请连接的客户端IP Port
//peerAddress:返回传来请求的IP,即客户端IP
//peerPort:返回传来请求的端口号,即客户端Port
QString ip = tcpSocket->peerAddress().toString();
quint16 port = tcpSocket->peerPort();
//在UI的edit中显示哪个客户端连接了本服务器:显示客户端IP Port
QString temp = QString("[%1:%2]已成功连接").arg(ip).arg(port);
ui->textEdit->setText(temp);
//设置文件连接按钮为可按
ui->buttonFile->setEnabled(true);
});
connect(&myTimer,&QTimer::timeout,[=](){
//关闭定时器
myTimer.stop();
sendData();//在发送文件信息20ms后发送文件内容,防止 粘包。
});
}
server::~server()
{
delete ui;
}
//“发送文件”按钮的槽函数
void server::on_buttonFile_clicked()
{
//getOpenFileName默认文件打开路径,参数:1、放弃2、标题3、路径
//返回打开文件路径
QString filepath = QFileDialog::getOpenFileName(this,"Open","../");
if(filepath.isEmpty() == false){ //文件路径是否存在
//获取文件信息:名 路径;info获得了选择的文件的名和路径
QFileInfo info(filepath);
//将用户选择的文件的名和地址赋给file,file是要接收并存储的文件
fileName = info.fileName();
fileSize = info.size();
sendSize = 0;//发送文件大小=0
//设置文件名
file.setFileName(filepath);
//打开文件为只读
//打开文件是否成功
bool isok = file.open(QIODevice::ReadOnly);
if(isok == false)
{
qDebug()<<"文件打开失败";
}
//文件路径显示
ui->textEdit->append(filepath);
ui->buttonFile->setEnabled(false);
ui->buttonSend->setEnabled(true);
}
else
{
qDebug()<<"文件路径选择失败";
}
}
//“发送文件”的槽函数
//由ui之间创建槽函数不用connect
void server::on_buttonSend_clicked()
{
//1、先发送文件信息
//str即要发送信息
QString str = QString("%1##%2").arg(fileName).arg(fileSize);//组包,可在客户端解包
//len:发送的字节数。发送文件信息
quint64 len = tcpSocket->write(str.toUtf8().data());
if(len>0)//发送消息成功
{
myTimer.start(20);//间隔20ms触发timeout信号
}
else
{
qDebug()<<"发送文件信息失败";
file.close();
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
void server::sendData()
{
qint64 len = 0;//len记录已经发送了多少文件
do
{
char buf[4*1024] = {0};
//读文件内容
len = file.read(buf,sizeof (buf));//读指定大小:buf的内容。返回的len:所读文件大小
//读多少发多少
len = tcpSocket->write(buf,len);//返回len:发送内容的大小
//统计发送文件大小
sendSize+=len;//已发送文件大小
}while(len>0);
if(sendSize == fileSize)//发送文件大小==文件总大小
{
//完毕是标题
QMessageBox::information(this,"完毕","文件传输完成");
qDebug()<<"sendsize = "<<sendSize<<" filesize = "<<fileSize;
//传输完断开连接
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}