Qt使用QTcpSocket及QTcpServer传输文件

2023-10-31

服务端具体代码如下:

.h
#include <QTcpServer>
#include <QTcpSocket>
#include <QFileDialog>
#include <QFile>
#define BUF_SIZE 1024*8
class ServerProject : public QWidget
{
    Q_OBJECT

public:
    ServerProject(QWidget *parent = nullptr);
    ~ServerProject();
    void iniServer();
    void closeServer();
    void sendData();
private slots:
    void on_listenBtn_clicked();
    void on_sendBtn_clicked();
    void on_clearRecBtn_clicked();
    void on_selectBtn_clicked();
    void on_sendFileBtn_clicked();
    void newConnectionSlot();
    void readyReadSlot();
private:
    Ui::ServerProjectClass ui;
	QTcpServer* m_server;
    QTcpSocket* m_socket;
    QString m_filename;
    int m_fileSize, m_sendSize;
    QFile m_file;
};
.cpp
ServerProject::ServerProject(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    setWindowTitle("Server");
    iniServer();
}
ServerProject::~ServerProject()
{
	closeServer();
	if (m_socket != NULL) {
		delete m_socket;
		m_socket = NULL;
	}
}
void ServerProject::iniServer() {
	//m_sendEnable = false;
	m_filename = "";
	m_fileSize = 0;
	m_sendSize = 0;
	m_socket = NULL;
	ui.clearRecBtn->setEnabled(false);
	ui.sendBtn->setEnabled(false);
	ui.selectBtn->setEnabled(false);
	ui.sendFileBtn->setEnabled(false);
    m_server = new QTcpServer(this);
}
void ServerProject::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 ServerProject::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, &ServerProject::newConnectionSlot);
	}
}
void ServerProject::newConnectionSlot() {
	if (m_server->hasPendingConnections())
	{
		//nextPendingConnection返回下一个挂起的连接作为已连接的QTcpSocket对象
		//套接字是作为服务器的子级创建的,这意味着销毁QTcpServer对象时会自动删除该套接字。
		//最好在完成处理后显式删除该对象,以避免浪费内存。
		//返回的QTcpSocket对象不能从另一个线程使用,如有需要可重写incomingConnection().
		m_socket = m_server->nextPendingConnection();
		ui.receiveEt->append("connected.........");
		connect(m_socket, &QTcpSocket::readyRead, this, &ServerProject::readyReadSlot);
		ui.clearRecBtn->setEnabled(true);
		ui.selectBtn->setEnabled(true);
		ui.sendBtn->setEnabled(true);
	}
}
void ServerProject::readyReadSlot() {
	if (m_socket->bytesAvailable() <= 0)
		return;
	//注意收发两端文本要使用对应的编解码
	const QString recv_text = QString::fromUtf8(m_socket->readAll());
	if (ui.sendFileBtn->isEnabled()) {
		ui.receiveEt->append(recv_text);
	}
	else {
		if (recv_text == "FileHead Succ") {
			qDebug() << "get FileHead Succ--------------";
			sendData();
		}
		else if (recv_text=="FileRec Done") {
			m_file.close();
			ui.sendBtn->setEnabled(true);
			ui.selectBtn->setEnabled(true);
			ui.sendFileBtn->setEnabled(true);
		}
	}
}
void ServerProject::on_sendBtn_clicked() {
	if (!m_server->isListening())
		return;
	//将发送区文本发送给客户端
	const QByteArray send_data = ui.sendEt->toPlainText().toUtf8();
	//数据为空就返回
	if (send_data.isEmpty())
		return;
	m_socket->write(send_data);
	ui.sendEt->clear();
}
void ServerProject::on_clearRecBtn_clicked() {
	ui.receiveEt->clear();
}
void ServerProject::on_selectBtn_clicked() {
	QString filePath = QFileDialog::getOpenFileName(this, "open", "../");
	if (!filePath.isEmpty()) {
		//m_sendEnable = false;
		m_filename = "";
		m_fileSize = 0;
		m_sendSize = 0;
		QFileInfo info(filePath);
		m_filename = info.fileName();
		m_fileSize = info.size();
		qDebug() << "slectfile name: " << m_filename << " size: " << m_fileSize;
		m_file.setFileName(filePath);
		if (m_file.open(QIODevice::ReadOnly)) {
			//m_sendEnable = true;
			ui.selectBtn->setEnabled(false);
			ui.sendBtn->setEnabled(false);
			ui.sendFileBtn->setEnabled(true);
		}
	}
}
void ServerProject::on_sendFileBtn_clicked() {
	QString filehead = QString("%1#%2").arg(m_filename).arg(m_fileSize);
	qint64 len = m_socket->write(filehead.toUtf8());
	if (len > 0) {
		qDebug() << "filehead:  " << filehead;
		ui.sendFileBtn->setEnabled(false);
	}
}
void ServerProject::sendData() {
	qint64 len = 0;
	do {
		//一次发送的大小
		char buf[BUF_SIZE] = { 0 };
		len = 0;
		len = m_file.read(buf, BUF_SIZE);  //读取的字节数
		len = m_socket->write(buf, len);    //发送的字节数
		qDebug() << "len-----" << len;
		//已发数据累加
		m_sendSize += len;
	} while (len > 0);
}

服务端代码如下:

ClientPro::ClientPro(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    initClient();
}
ClientPro::~ClientPro()
{
	qDebug() << "~ClientPro()----------------------------";
	if (m_client->state() == QAbstractSocket::ConnectedState) {
		//如果使用disconnectFromHost()不会重置套接字,isValid还是会为true
		m_client->abort();
	}
}
void ClientPro::initClient() {
	m_fileMaxsize = 100;
	m_sendEnable = false;
	//创建client对象
	m_client = new QTcpSocket(this);
}
void ClientPro::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 {
		ui.receiveEt->append("It is not ConnectedState or UnconnectedState");
	}
	connect(m_client, &QTcpSocket::connected, this, &ClientPro::connectedSlot);
	connect(m_client, &QTcpSocket::disconnected, this, &ClientPro::disconnectedSlot);
	connect(m_client, &QTcpSocket::readyRead, this, &ClientPro::readyReadSlot);
}
void ClientPro::connectedSlot() {
	ui.connectBtn->setText("Disconnect");
	ui.addressEt->setEnabled(false);
	ui.portEt->setEnabled(false);
}
void ClientPro::disconnectedSlot() {
	ui.connectBtn->setText("Connect");
	ui.addressEt->setEnabled(true);
	ui.portEt->setEnabled(true);
}
void ClientPro::readyReadSlot() {
	if (m_client->bytesAvailable() <= 0)
		return;
	//注意收发两端文本要使用对应的编解码
	QByteArray buf = m_client->readAll();
	const QString recv_text = QString::fromUtf8(buf);

	QStringList list = recv_text.split("#");
	qDebug() << "listsize: " << list.size();
	if (!m_sendEnable&&list.size() == 2) {
		m_sendEnable = true;
		ui.sendBtn->setEnabled(false);
		m_recSize = 0;
		m_client->write("FileHead Succ");
		m_file.setFileName(list[0]);
		m_fileMaxsize = list[1].toInt();
		ui.progressBar->setValue(m_recSize);
		ui.progressBar->setMaximum(m_fileMaxsize);
		if (m_file.open(QIODevice::WriteOnly)) {
			return;
		}
	}
	if (!m_sendEnable) {
		ui.receiveEt->append(recv_text);
	}
	else {
		qint64 len = m_file.write(buf);
		m_recSize += len;
		qDebug() << "client----m_recSize: " << m_recSize;
		ui.progressBar->setValue(m_recSize);
		if (m_recSize == m_fileMaxsize) {
			qDebug() << "rec done--------------";
			m_sendEnable = false;
			m_file.close();
			m_client->write("FileRec Done");
			ui.sendBtn->setEnabled(true);
		}
	}
}
void ClientPro::on_sendBtn_clicked() {
	if (!m_client->isValid())
		return;
	//将发送区文本发送给客户端
	const QByteArray send_data = ui.sendEt->toPlainText().toUtf8();
	//数据为空就返回
	if (send_data.isEmpty())
		return;
	m_client->write(send_data);
}
void ClientPro::on_clearRecBtn_clicked() {
	ui.receiveEt->clear();
}
void ClientPro::on_clearSendBtn_clicked() {
	ui.sendEt->clear();
}

动态显示如下:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt使用QTcpSocket及QTcpServer传输文件 的相关文章

随机推荐

  • WPF的MVVM框架Stylet开发文档 17.设计模式支持

    17 设计模式支持 介绍 设计模式 或 设计时 是指当您的项目加载到 Visual Studio XAML 设计器或 Expression Blend 中时 您将看到 XAML 的渲染版本 大多数时候 设计者不会尝试评估您的任何绑定或为它们
  • ip、子网掩码、网关、默认网关

    这里写目录标题 ip 网络地址 主机地址 子网 子网掩码 子网掩码的表示方法 为什么要使用子网掩码 子网掩码的分类 网关 默认网关 ip ip地址 网络地址 主机地址 又称 网络号和主机号 我们把网络号相同的主机称之为本地网络中的主机 网络
  • JVM跨平台原理

    Java有一个其他语言都没有特点 那就是跨平台 跨平台是什么意思呢 我们首先来看看平台是指什么 平台就是指我们计算机的操作系统 例如 Windows Linux Mac等操作系统 跨平台的意思就是Java程序 在一次编译后 在这些平台上都可
  • 混淆技术研究-OLLVM混淆-控制流平坦化(FLA) - WIP

    简介 控制流平坦化通过将程序中的条件分支语句转化为等价的平铺控制流来实现 通常 这包括将原始的分支语句 如if语句 switch语句 中的每个分支提取出来 并将它们放置在一系列连续的基本块中 然后使用一个状态变量或标志来选择要执行的基本块
  • C++ 虚继承和多态性

    类体系的函数重载 在一个类中声明重载 派生类定义和基类同名 同参数的函数 即在派生类中重载 类指针的关系 基类指针指向基类对象 派生类指针指向派生类对象 基类指针指向派生类对象 派生类指针指向基类对象 基类指针可以直接指向派生类对象 但是使
  • 线程的锁问题

    1 公平锁与非公平锁 公平锁 排队进行 非公平锁 抢占式 同步代码块 同步方法都属于非公平锁 显式锁Lock可以指定是否为公平锁 true 公平锁 false 给公平锁 默认 private Lock l new ReentrantLock
  • 7.反引号 ` `

    1 反引号第一种使用情况 fun main 登录功能 2021年8月8日测试环境下 测试登录功能 需求编码人是Derry Derry 123456 private fun 登录功能 2021年8月8日测试环境下 测试登录功能 需求编码人是D
  • selenium自动化测试实战案例哔哩哔哩信息至Excel

    文章目录 前言 明确目标 最终效果 开发环境 思路分析 实现步骤 运行效果 以下是全部代码 前言 最近在B站学习知识 于是看完了视频就想着练习一下巩固一下知识 就地取材的做了个B站selenium小项目 感觉还挺适合新手入门的 于是迫不及待
  • LeetCode-410.最小区间、滑动窗口、双指针

    你有 k 个升序排列的整数数组 找到一个最小区间 使得 k 个列表中的每个列表至少有一个数包含在其中 我们定义如果 b a lt d c 或者在 b a d c 时 a lt c 则区间 a b 比 c d 小 示例 1 输入 4 10 1
  • 【chineseocr_lite】踩的坑

    chineseocr lite版本 https github com ouyanghuiyu chineseocr lite git 最重要的电脑环境 v100服务器 cuda10 python3 6 环境对了就成功90 另本环境是cuda
  • UWB自组网定位方案_基于UWB技术的消防应急救援定位解决方案

    目前国内应急救援市场都是基于被动定位应用 在特殊情况下救援也大多处于单兵作战的情况 并不能及时知道自己和自己组员的位置信息和状态 且没有场景感知和室内外一体位置信息结合 使相关救援人员处于更加危险境地 本篇就带大家详细了解一下微能信息针对消
  • JDBC中的Connection

    jdbc中的Connection连接基本用法 package Jdbc import java sql Connection import java sql DriverManager import java sql SQLExceptio
  • Google Sign In error 12500

    接入Google登录遇到12500报错 网上查到的原因是后台配置包的签名哈希值不正确 但是我们的应用并没有使用firebase管理 尝试多次之后终于找到了解决方法 在开发者后台应用管理界面 创建一个新的凭据 类型为Andorid 该凭据下包
  • 层层优化重复代码,我又搞了一个通用模板

    后端思维 最近工作中 我通过层层优化重复代码 最后抽出个通用模板 因此跟大家分享一下优化以及思考的过程 我会先造一个相似的例子 然后一步步带大家如何优化哈 看完一定会有帮助的 优化前的例子 第一步优化 抽取公用方法 第二步优化 反射对比字段
  • 除了李飞飞,那些影响 AI 技术发展的女性工程师

    自 1911 年以来 国际妇女节已经走过了一个多世纪 我们为一个更平等的世界努力过 并且仍将继续努力 近年来 随着数据科学和机器学习的迅猛发展 AI 从业者的需求激增 然而 人工智能领域女性从业者的数量远低于男性 根据 Wired 和 El
  • 〖Web全栈开发②〗—网络编程基础(下)

    Web全栈开发 网络编程基础 下 一 TCP 网络应用程序开发流程 1 TCP 网络应用程序开发流程的介绍 2 TCP 客户端程序开发流程的介绍 3 TCP 服务端程序开发流程的介绍 4 小结 二 socket之send和recv原理剖析
  • Java BIO API及代码测试

    文章目录 0 网络编程 1 JAVA最初的网络应用 BIO 1 1服务端代码编写 1 2客户端代码编写 1 3升级版服务端代码 支持同时处理多连接 1 4再次升级服务端代码 支持浏览器请求 2 拓展学习 ServerSocket 类 及AP
  • 蓝桥杯算法提高VIP-队列操作

    题目 题目链接 题解 模拟队列 代码 include
  • 删除vim打开文件末尾的^M

    最近在Windows下写了一个shell脚本 拿到Linux下执行的时候一直提示找不到文件 但是文件明明就存在 在Linux用vi vim 打开脚本 文件内容不为空 仔细检查脚本内容也没有出错 只是每行 末尾 多出来一个 M 符号 去掉这个
  • Qt使用QTcpSocket及QTcpServer传输文件

    服务端具体代码如下 h include