使用QTcpSocket及QTcpServer传输大文件

这篇具有很好参考价值的文章主要介绍了使用QTcpSocket及QTcpServer传输大文件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Qt在实际的使用Tcp通信中发现,发送端与接收端并不是一一对应的,会出现发送多次只相应一次的情况,且发送端速度远超接收端时会引起程序崩溃,小文件不存在这样的问题,可忽略,大文件发送之所以出现,其问题的根本点在于Tcp发送与接收端不一致引起的粘包。
因此可根据实际情况制定协议,使用一问一答的方式进行数据传输,牺牲效率以满足稳定性和安全可靠性。

客户端代码如下

TcpClientPro::TcpClientPro(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
	initClient();
}
TcpClientPro::~TcpClientPro()
{
	qDebug() << "~ClientPro()----------------------------";
	if (m_client->state() == QAbstractSocket::ConnectedState) {
		//如果使用disconnectFromHost()不会重置套接字,isValid还是会为true
		m_client->abort();
	}
}
void TcpClientPro::initClient() {
	//创建client对象
	m_client = new QTcpSocket(this);
	ui.selectBtn->setEnabled(false);
	ui.sendBtn->setEnabled(false);
}
void TcpClientPro::on_connectBtn_clicked() {
	if (m_client->state() == QAbstractSocket::ConnectedState) {
		//如果使用disconnectFromHost()不会重置套接字,isValid还是会为true
		m_client->abort();
	}
	else if (m_client->state() == QAbstractSocket::UnconnectedState) {
		//从界面上读取ip和端口
		const QHostAddress address = QHostAddress(ui.addressEt->text());
		const unsigned short port = ui.portEt->text().toUShort();
		//连接服务器
		m_client->connectToHost(address, port);
	}
	else {
		
	}
	connect(m_client, &QTcpSocket::connected, this, &TcpClientPro::connectedSlot);
	connect(m_client, &QTcpSocket::disconnected, this, &TcpClientPro::disconnectedSlot);
	connect(m_client, &QTcpSocket::readyRead, this, &TcpClientPro::readyReadSlot);
}
void TcpClientPro::on_selectBtn_clicked() {
	QString filePath = QFileDialog::getOpenFileName(this, "open", "../");
	if (!filePath.isEmpty()) {
		m_fileName = "";
		QFileInfo info(filePath);
		m_fileName = info.fileName();
		qDebug() << "m_fileName----------" << m_fileName;
		m_file.setFileName(filePath);
		if (m_file.open(QIODevice::ReadOnly)) {

			FileDate fdata;
			int size = m_file.size();
			if (size == 0) {
				m_file.close();
				return;
			}
			m_lastSize = size % sizeof(fdata.data);
			m_readNum = size / sizeof(fdata.data) + (m_lastSize > 0 ? 1 : 0);
			QByteArray array1 = m_fileName.toStdString().c_str();//
			strncpy(fdata.fileName, array1.data(), sizeof(fdata.fileName));//
			//fdata.FileName = m_fileName;
			fdata.readCnt = m_readNum;
			fdata.lastSize = m_lastSize;
			fdata.type = TransFileInfo;
			qDebug() << "sizeof(fdata)-----------------------" << sizeof(fdata);
			QByteArray array;
			array.resize(sizeof(fdata));
			memcpy(array.data(), &fdata, sizeof(fdata));//把结构体存入数组
			m_client->write(array);
			m_client->waitForBytesWritten();
		}
	}
}
void TcpClientPro::on_sendBtn_clicked() {

}
void TcpClientPro::connectedSlot() {
	ui.connectBtn->setText("Disconnect");
	ui.selectBtn->setEnabled(true);
	ui.addressEt->setEnabled(false);
	ui.portEt->setEnabled(false);
}
void TcpClientPro::disconnectedSlot() {
	ui.connectBtn->setText("Connect");
	ui.addressEt->setEnabled(true);
	ui.portEt->setEnabled(true);
	ui.selectBtn->setEnabled(false);
	ui.sendBtn->setEnabled(false);
}
void TcpClientPro::readyReadSlot() {
	if (m_client->bytesAvailable() <= 0)
		return;
	FileDate fdata;
	QByteArray array;
	array = m_client->readAll();
	memcpy(&fdata, array.data(), sizeof(fdata));//转化到结构体
	if (fdata.state == CorrectState) {
		if (fdata.type == TransFileInfoDone) {
			m_readIndex = 0;
			readFileData();
		}
		else if (fdata.type == TransFileData) {
			readFileData();
		}
		if (m_readIndex == m_readNum) {
			m_file.close();
		}
	}
	else {
		m_file.close();
	}
}
void TcpClientPro::readFileData() {
	QByteArray r_array;
	FileDate r_fdata;
	r_array.resize(sizeof(r_fdata));
	r_fdata.type = TransFileData;
	m_file.read(r_fdata.data, sizeof(r_fdata.data));
	memcpy(r_array.data(), &r_fdata, sizeof(r_fdata));//把结构体存入数组
	m_client->write(r_array);
	m_client->waitForBytesWritten(1000);
	m_readIndex++;
	qDebug() << "TcpClientPro::readFileData----" << m_readIndex;
}

服务端代码如下:


```go
TcpServerPro::TcpServerPro(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
	setWindowTitle("Server");
	iniServer();
}
TcpServerPro::~TcpServerPro()
{
	closeServer();
	if (m_socket != NULL) {
		delete m_socket;
		m_socket = NULL;
	}
}
void TcpServerPro::iniServer() {
	m_fileName = "";
	m_readCnt = 0;
	m_lastSize = 0;
	m_socket = NULL;
	ui.clearBtn->setEnabled(false);
	m_server = new QTcpServer(this);
}
void TcpServerPro::closeServer() {
	m_server->close();
	if (m_socket == NULL) {
		return;
	}
	//断开与客户端的连接
	if (m_socket->state() == QAbstractSocket::ConnectedState) {
		m_socket->disconnectFromHost();
		if (m_socket->state() != QAbstractSocket::UnconnectedState) {
			m_socket->abort();
		}
	}
}
void TcpServerPro::on_listenBtn_clicked() {
	if (m_server->isListening()) {
		closeServer();
		//关闭server后恢复界面状态
		ui.listenBtn->setText("Listen");
		ui.addressEt->setEnabled(true);
		ui.portEt->setEnabled(true);
	}
	else {
		//可以使用 QHostAddress::Any 监听所有地址的对应端口
		const QString address_text = ui.addressEt->text();
		const unsigned short port = ui.portEt->text().toUShort();
		const QHostAddress address = (address_text == "Any")
			? QHostAddress::Any
			: QHostAddress(address_text);
		//开始监听,并判断是否成功
		if (m_server->listen(address, port)) {
			//连接成功就修改界面按钮提示,以及地址栏不可编辑
			ui.listenBtn->setText("Close");
			ui.addressEt->setEnabled(false);
			ui.portEt->setEnabled(false);
		}
		connect(m_server, &QTcpServer::newConnection, this, &TcpServerPro::newConnectionSlot);
	}
}
void TcpServerPro::on_clearBtn_clicked() {
	ui.receiveEt->clear();
}
void TcpServerPro::newConnectionSlot() {
	if (m_server->hasPendingConnections())
	{
		//nextPendingConnection返回下一个挂起的连接作为已连接的QTcpSocket对象
		//套接字是作为服务器的子级创建的,这意味着销毁QTcpServer对象时会自动删除该套接字。
		m_socket = m_server->nextPendingConnection();
		ui.receiveEt->append("connected.........");
		connect(m_socket, &QTcpSocket::readyRead, this, &TcpServerPro::readyReadSlot);
		ui.clearBtn->setEnabled(true);
	}
}
void TcpServerPro::readyReadSlot() {
	if (m_socket->bytesAvailable() <= 0)
		return;
	FileDate fdata;
	QByteArray array;
	//array.resize(sizeof(fdata));
	array = m_socket->readAll();
	memcpy(&fdata, array.data(), sizeof(fdata));//转化到结构体
	if (fdata.type == TransFileInfo) {
		parseFileData(fdata);
	}
	else if (fdata.type == TransFileData) {
		writeFile(fdata);
	}
}
void TcpServerPro::writeFile(FileDate& fdata) {
	m_readIndex++;
	ui.progressBar->setValue(m_readIndex);
	if (m_readIndex == m_readCnt)//最后一个包
	{
		m_file.write(fdata.data, m_lastSize);
		m_readIndex = 0;
		m_file.close();//传输完毕
		qDebug() << "transfer over------------------------";
		return;
	}
	else {
		m_file.write(fdata.data, sizeof(fdata.data));
		QByteArray array1;
		array1.resize(sizeof(fdata));
		FileDate buf;
		buf.state = CorrectState;
		buf.type = TransFileData;
		memcpy(array1.data(), &buf, sizeof(buf));
		qDebug() << "transfer progress-------" << double(1.0*m_readIndex / m_readCnt) * 100<<"%";
		m_socket->write(array1);
		m_socket->waitForBytesWritten(1000);
	}
}
void TcpServerPro::parseFileData(FileDate &fdata) {
	QString dirname = QFileDialog::getExistingDirectory(this, "SelectDirectory", "/");
	QString filename(fdata.fileName);
	//qDebug() << "dirname: " << dirname;
	QString filePath = dirname.append("/").append(filename);
	QFileInfo info(filePath);
	m_fileName = info.fileName();
	m_readCnt = fdata.readCnt;
	m_lastSize = fdata.lastSize;
	qDebug() << "TcpServerPro::parseFileData m_readCnt: " << m_readCnt << " m_lastSize: " << m_lastSize;
	m_file.setFileName(filePath);
	FileDate fdata1;
	if (m_file.open(QIODevice::WriteOnly)) {
		fdata1.type = TransFileInfoDone;
		fdata1.state = CorrectState;
		ui.progressBar->setMaximum(m_readCnt);
		ui.progressBar->setValue(0);
	}
	else {
		fdata1.type = TransFileData;
		fdata1.state = ErrorState;
	}
	m_readIndex = 0;
	QByteArray array1;
	array1.resize(sizeof(fdata1));
	memcpy(array1.data(), &fdata1 , sizeof(fdata1));
	m_socket->write(array1);
	m_socket->waitForBytesWritten();
}

动态显示效果如下:
qt tcp接收大文件,Qt,qt,tcp/ip文章来源地址https://www.toymoban.com/news/detail-705865.html

到了这里,关于使用QTcpSocket及QTcpServer传输大文件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • QT中TCP文件传输

    *免责声明: 1、视频来源于传智播客 2、此方法仅提供参考 本文代码根据B站《零基础入门六天学会QT完整版》中的P52和P53,其中视频有缺失,为了造福其他兄弟,在此补上缺失代码 首先需要创建两个类:ServerWidget和ClientWidget类 以上就是视频中TCP文件传输的代码,若有发现错误

    2023年04月25日
    浏览(37)
  • QT-通过tcp传输文件和文本消息

    在建立连接的基础上增加了发送文件的功能,在接收端和发送端定义了一个枚举类型,用于判别发送的是文件还是文本消息 客户端ui 1.获取端口号和ip地址,进行连接,再次点击即可断开连接 2.点击发送消息按钮,获取文本框内容,将消息发送出去,其中type为文本消息类型

    2024年02月03日
    浏览(36)
  • Qt开发-TCP/IP网络通信(以及文件传输)

    TCP/IP通信(即SOCKET通信)是通过网线将 服务器Server端 和 客户机Client端 进行连接,在遵循ISO/OSI模型的四层层级构架的基础上通过TCP/IP协议建立的通讯。控制器可以设置为服务器端或客户端。 关于TCP/IP协议可详看:TCP/IP协议详解 - 知乎 (zhihu.com) 总的来说,TCP/IP通讯有两个部分

    2024年02月10日
    浏览(52)
  • Qt详解实现TCP文件传输例子(文件下载和上传)附源码

    网络通信我们用的很频繁,如文字,语音,文件,图片等,这个些传输方式都差不多 QT文件传输主要考验对传输的控制,还是需要点逻辑的,文件传输的大致框架如下 先看一下简单例子实现的效果(界面有点丑,重点在于内容):  接下来重点讲一下需要用到哪些东西: 1.数

    2024年02月16日
    浏览(41)
  • Qt多线程TCP服务器客户端传输文件

    TCP是面向连接的运输层协议。应用程序在使用TCP协议之前,必须先建立TCP连接。在传送数据完毕后,必须释放已经建立的TCP连接。 每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的(一对一)。 TCP提供可靠交付的服务。通过TCP 连接传送的数据,无差错、不丢失、不

    2024年02月13日
    浏览(55)
  • 5. QT环境下使用OPenCV(基于TCP实现摄像头图像数据的多线程传输)

    1. 说明 通常情况下对于图像数据的采集可以放在后端进行,采集到的图像数据如果有需要可以通过通信将数据传输到前端进行显示,这其中需要使用到TCP数据传输协议和QT下的多线程开发技术。 QT当中主线程一般是界面层次的,在主线程中执行耗时较长的数据操作,会引起界

    2024年02月11日
    浏览(63)
  • 【QT实现TCP数据发送和接收】

    单客户端服务器实现代码: 在.pro文件添加 在头文件中添加 在源文件中添加

    2024年02月11日
    浏览(53)
  • QT下TCP协议实现数据网络传输

    QT开发框架以其跨平台的优势,在全世界IT界如雷贯耳。其封装了功能齐全的各种类,大大的提高了开发者的效率。本篇内容将介绍如何使用QT 6.4.1框架开发服务器和客户端程序,让两端能够首发消息,服务端往客户端发送文件(客户端往服务器发送类似,没有实现)。  说明

    2023年04月08日
    浏览(47)
  • 网络通信/QTcpSocket/实现一个可在子线程中发送和接收数据的TCP客户端

    近来一直接使用WinSocket做网络编程,有很长一段时间不再使用Qt框架下的相关网路通信类。有不少之前积压的问题直到现在也没怎么弄清楚,在CSDN中乱七八糟的存了好几篇草稿,亟待整理。最近要写一个简单地相机升级程序,于是重操旧业。 网络通信中,尤其是在收发工作较

    2024年02月08日
    浏览(55)
  • Qt的TCP传输数据,出现中文乱码的解决方案

    Qt的TCP传输数据中文乱码的问题,可能是由于编码不一致导致的。可以尝试以下方法解决: 在发送数据之前,将中文字符串进行编码转换。例如,将QString类型的中文字符串转换成UTF-8编码的字节数组,可以使用QString的toUtf8()函数,示例代码如下: QString str = \\\"中文字符串\\\"; QB

    2024年02月09日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包