QT中的服务器与客户端

一、前言

        本文主要讲讲QT中服务器与客户端的使用方法,QT已经封装好了,调用相应类直接访问即可。本文以QT中的QT中的TCP为例子,讲下使用方法以及线程中使用。

二、正文

2.1 Sever的使用方法

2.1.1 思路

QT中Sever使用的时候大致步骤为:

1、创建监听的服务器对象

2、监听到数据信号,创建QTcpSocket的套接字对象

3、检测是否可以接收数据

4、信息发送,查看数据发送是否正常

总的来说,就是先确定要监听的地址与端口,然后数据在套接字中,套接字在QT中是QTcpSocket

封装的类,直接用就行,最后通过套接字接收数据或者发送数据即可。

2.1.2 代码示例

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
    QTcpServer *m_server;
    QTcpSocket *m_tcp;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    ui->lineEdit_port->setText("8888");

    //创建监听的服务器对象
    m_server = new QTcpServer(this);
    connect(ui->pushButton_listen, &QPushButton::clicked, this, [=](){
        m_server->listen(QHostAddress::Any, ui->lineEdit_port->text().toInt());
        ui->pushButton_listen->setDisabled(true);
    });

    //监听到数据信号,创建QTcpSocket的套接字对象
    connect(m_server, &QTcpServer::newConnection, this, [=](){
        m_tcp = m_server->nextPendingConnection();

        //检测是否可以接收数据
        connect(m_tcp, &QTcpSocket::readyRead, this, [=](){
            QByteArray data = m_tcp->readAll();
            ui->textEdit_historymsg->append("客户端说: " + data);
        });
    });

    //信息发送
    connect(ui->pushButton_send, &QPushButton::clicked, this, [=](){
        QString msg = ui->textEdit_sendmsg->toPlainText();
        m_tcp->write(msg.toUtf8());
        ui->textEdit_historymsg->append("服务器说: " + msg);
    });

}

Widget::~Widget()
{
    delete ui;
}

2.1.3 细节讲解

创建服务器对象QTcpServer,对象有监听的方法listen。

监听的地址设置所有即可访问你电脑可以收到的所有地址,可以用win+R进入cmd查看有哪些,比如:

获取到新的连接后,将下一个挂起的连接作为已连接的QTcpSocket对象返回

准备读取信号有了后即可开始读取套接字内的数据。

2.1.4 演示

监听成功

2.2 Client的使用方法

2.2.1 思路

QT中Client使用的时候大致步骤为:

1、创建Socket对象,连接服务器

2、数据交互

3、根据需求断开连接

总体来说很简单,套接字连接好服务器的地址与端口即可,前提是服务器开启了,不然连接会失败。

2.2.2 代码示例

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpSocket>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
    QTcpSocket *m_socket;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"

#include <QHostAddress>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    ui->lineEdit_address->setText("192.168.2.24");
    ui->lineEdit_connect->setText("8888");

    //创建Socket对象,连接服务器
    m_socket = new QTcpSocket(this);
    connect(ui->pushButton_connect, &QPushButton::clicked, this, [=](){
        m_socket->connectToHost(QHostAddress(ui->lineEdit_address->text()), ui->lineEdit_connect->text().toInt());
        ui->pushButton_connect->setDisabled(true);
        ui->pushButton_close->setEnabled(true);
    });

    //断开连接
    connect(ui->pushButton_close, &QPushButton::clicked, this, [=](){
        m_socket->close();
        ui->pushButton_connect->setEnabled(true);
        ui->pushButton_close->setDisabled(true);
    });

    //数据交互
    connect(m_socket, &QTcpSocket::connected, this, [=](){
        ui->textEdit_history->append("服务器连接成功!!!!");
    });
    connect(m_socket, &QTcpSocket::readyRead, this, [=](){
        ui->textEdit_history->append("服务器说: " + m_socket->readAll());
    });
    connect(m_socket, &QTcpSocket::disconnected, this, [=](){
        ui->textEdit_history->append("服务器断开连接!!!!");
    });
    connect(ui->pushButton_send, &QPushButton::clicked, this, [=](){
        m_socket->write(ui->textEdit_send->toPlainText().toUtf8());
        ui->textEdit_history->append("客户端说: " + ui->textEdit_send->toPlainText().toUtf8());
    });
}

Widget::~Widget()
{
    delete ui;
}

2.2.3 细节讲解

没啥可讲的,QT都封装好了,连接好就能直接用,比串口的请求响应简单方便多了。

2.2.4 演示

注意,先开启服务器,然后才能使用,局域网可以内部使用,外部使用需要申请IP。

2.3 线程中的使用

在实际项目中,数据的部分大多是写进线程的,关于线程的了解在前文中有讲述,需要的朋友可以自行查阅。

下面以文件从客户端传到服务器为例:

2.3.1 代码示例

2.3.1.1 Sever
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTcpServer>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pushButton_listen_clicked();

private:
    Ui::MainWindow *ui;
    QTcpServer* m_server;

};
#endif // MAINWINDOW_H
#ifndef ACCEPTFILE_H
#define ACCEPTFILE_H

#include <QObject>
#include <QThread>
#include <QTcpSocket>

class acceptfile : public QThread
{
    Q_OBJECT
public:
    explicit acceptfile(QTcpSocket* tcp, QThread *parent = nullptr);

signals:
    void over();

protected:
    void run() override;

private:
    QTcpSocket* m_tcp;

};

#endif // ACCEPTFILE_H
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "acceptfile.h"

#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //创建服务器对象
    m_server = new QTcpServer(this);
    //创建套接字
    connect(m_server, &QTcpServer::newConnection, this, [=](){
        QTcpSocket* tcp = m_server->nextPendingConnection();
        //创建子线程
        acceptfile* subthread = new acceptfile(tcp);
        subthread->start();

        //释放资源
        connect(subthread, &acceptfile::over, this, [=](){
            subthread->quit();
            subthread->wait();
            subthread->deleteLater();
            QMessageBox::information(this, "文件接收", "文件接收完毕!!!!!!!");
        });
    });

}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_pushButton_listen_clicked()
{
    m_server->listen(QHostAddress::Any, ui->lineEdit_port->text().toUShort());
}
#include "acceptfile.h"

#include <QFile>


acceptfile::acceptfile(QTcpSocket* tcp, QThread *parent) : QThread(parent)
{
    m_tcp = tcp;
}

void acceptfile::run()
{
    //创建文件对象,保存客户端发送过来的文件内容
    QFile* file = new QFile("C:/Users/EDY/Desktop/QTtest/recv.txt");
    file->open(QFile::WriteOnly);
    //读取套接字socket的内容
    connect(m_tcp, &QTcpSocket::readyRead, this, [=](){
        static int total = 0;
        static int count = 0;
        if(count == 0)
        {
            m_tcp->read((char*)&total, 4);
        }
        //读出剩余数据
        QByteArray all = m_tcp->readAll();
        count += all.size();
        file->write(all);

        //判断是否接收完毕
        if(total == count)
        {
            m_tcp->close();
            m_tcp->deleteLater();
            file->close();
            file->deleteLater();
            emit over();
        }
    });
    //进入事件循环
    exec();
}
2.3.1.2 Client
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include <QThread>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

signals:
    void startconnect(unsigned short, QString);
    void sendFile(QString path);

private slots:
    void on_connectserver_btn_clicked();

    void on_file_btn_clicked();

    void on_send_btn_clicked();

private:
    Ui::MainWindow *ui;

};
#endif // MAINWINDOW_H
#ifndef SENDFILE_H
#define SENDFILE_H

#include <QObject>
#include <QTcpSocket>

class sendfile : public QObject
{
    Q_OBJECT
public:
    explicit sendfile(QObject *parent = nullptr);

    //连接服务器
    void connectServer(unsigned short address, QString ip);

    //发送文件
    void sendFile(QString path);

signals:
    void connectOK();
    void gameover();
    void curpercent(int);

private:
    QTcpSocket* m_tcp;

};

#endif // SENDFILE_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "sendfile.h"

#include <QFileDialog>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    ui->port->setText("8888");
    ui->IP->setText("192.168.2.24");
    ui->progressBar->setRange(0, 100);
    ui->progressBar->setValue(0);

    //创建线程对象
    QThread* thrd = new QThread;
    //创建任务
    sendfile* worker = new sendfile;
    //将work放入子线程
    worker->moveToThread(thrd);
    //连接服务器
    connect(this, &MainWindow::startconnect, worker, &sendfile::connectServer);
    //连接文件发送
    connect(this, &MainWindow::sendFile, worker, &sendfile::sendFile);
    //处理连接服务器的子线程数据
    connect(worker, &sendfile::connectOK, this, [=](){
        QMessageBox::information(this, "连接服务器",  "连接成功!!!!");
    });
    connect(worker, &sendfile::gameover, this, [=](){
        //资源释放
        thrd->quit();
        thrd->wait();
        worker->deleteLater();
        thrd->deleteLater();
    });
    //处理选择文件发送子线程数据
    connect(worker, &sendfile::curpercent, ui->progressBar, &QProgressBar::setValue);

    //线程开始
    thrd->start();
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_connectserver_btn_clicked()
{
    QString ip = ui->IP->text();
    unsigned short port = ui->port->text().toUShort();
    emit startconnect(port, ip);
}

void MainWindow::on_file_btn_clicked()
{
    QString path = QFileDialog::getOpenFileName();
    if(path.isEmpty())
    {
        QMessageBox::warning(this, "打开文件", "选择的文件路径不能为空!!");
        return;
    }
    ui->file->setText(path);
}

void MainWindow::on_send_btn_clicked()
{
    emit sendFile(ui->file->text());
}
#include "sendfile.h"

#include <QFile>
#include <QFileInfo>

sendfile::sendfile(QObject *parent) : QObject(parent)
{

}

void sendfile::connectServer(unsigned short address, QString ip)
{
    m_tcp = new QTcpSocket;
    m_tcp->connectToHost(ip, address);
    connect(m_tcp, &QTcpSocket::connected, this, &sendfile::connectOK);
    connect(m_tcp, &QTcpSocket::disconnected, this, [=](){
        m_tcp->close();
        m_tcp->deleteLater();
        emit gameover();
    });
}

void sendfile::sendFile(QString path)
{
    QFile file(path);
    QFileInfo info(path);

    int filesize = info.size();

    file.open(QFile::ReadOnly);

    while (!file.atEnd())
    {
        static int num = 0;
        if(num == 0)
        {
            m_tcp->write((char*)&filesize, 4);
        }
        QByteArray line = file.readLine();
        num += line.size();
        int percent = (num * 100 / filesize);
        emit curpercent(percent);

        m_tcp->write(line);
    }
}

2.3.2 代码讲解

没啥好讲的,可以看看代码,写得很详细,文件传输部分跟普通数据也是一样的,区别就是需要用到文件的类QFile和QFileInfo,一个是文件对象,一个是文件信息对象。简单来说指文件是QFile,指文件的具体数据是QFileInfo。源码已上传

2.3.3 演示

QTcp服务器与客户端

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/494817.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《论文阅读》PAGE:一个用于会话情绪原因蕴含基于位置感知的图模型 ICASSP 2023

《论文阅读》PAGE&#xff1a;一个用于会话情绪原因蕴含基于位置感知的图模型 ICASSP 2023 前言 简介任务定义模型构架Utterances Encoding with EmotionPosition-aware GraphCausal Classifier实验结果 前言 亲身阅读感受分享&#xff0c;细节画图解释&#xff0c;再也不用担…

【QQ版】QQ群短剧机器人源码 全网短剧机器人插件

内容目录 一、详细介绍二、效果展示2.效果图展示 三、学习资料下载 一、详细介绍 QQ版本可以兼容两个框架&#xff08;HTQQ&#xff0c;MYQQ这两个的vip版也可以使用) 支持私聊与群聊&#xff0c;命令是 搜剧影视关键词 如果无法搜索到影视资源&#xff0c;请使用下方命令&…

【LVGL-键盘部件,实体按键控制】

LVGL-二维码库 ■ LVGL-键盘部件■ 示例一&#xff1a;键盘弹窗提示■ 示例二&#xff1a;设置键盘模式■ 综合示例&#xff1a; ■ LVGL-实体按键控制■ 简介 ■ LVGL-键盘部件 ■ 示例一&#xff1a;键盘弹窗提示 lv_keyboard_set_popovers(kb,true);■ 示例二&#xff1a;设…

Spring boot2.X 配置https

背景 最近项目组说要将 http 升级成 https 访问&#xff0c;证书也给到我们这边了&#xff0c;当然我们这边用的是个二级域名&#xff0c;采用的是通配符访问的方式&#xff0c;比如一级域名是这样&#xff08;com.chinaunicom.cn&#xff09;&#xff0c;我们的则是&#xff0…

java数据结构与算法刷题-----LeetCode744. 寻找比目标字母大的最小字母

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 二分查找 二分查找 解题思路&#xff1a;时间复杂度O( l o g 2 …

vue2高德地图选点

<template><el-dialog :title"!dataForm.id ? 新建 : isDetail ? 详情 : 编辑" :close-on-click-modal"false" :visible.sync"show" class"rv-dialog rv-dialog_center" lock-scroll width"74%" :before-close&q…

神经网络:梯度下降法更新模型参数

作者&#xff1a;CSDN _养乐多_ 在神经网络领域&#xff0c;梯度下降是一种核心的优化算法&#xff0c;本文将介绍神经网络中梯度下降法更新参数的公式&#xff0c;并通过实例演示其在模型训练中的应用。通过本博客&#xff0c;读者将能够更好地理解深度学习中的优化算法和损…

五种方案图文并茂教你使用DBeaver,SQL文件导入数据库,插入数据,备份恢复mysql,postgres数据

文章目录 备份导出数据方案一&#xff1a;支持可以整个库导出、部分表导出、多个库导出&#xff08;可选格式较少&#xff09;使用连接数据库鼠标右键选择需要导出备份的数据库-工具-备份勾选需要导出的表-点击下一步设置输出目录和输出名称-点击开始导出成功 方案二&#xff1…

如何查看局域网IP?

在日常使用计算机和网络时&#xff0c;我们经常需要查看本地设备在局域网中的IP地址&#xff0c;以便进行一些网络配置或者连接其他设备。本文将介绍如何查看局域网中的IP地址&#xff0c;以及相关技术中的天联组网优势。 查看局域网IP 在Windows操作系统中&#xff0c;我们可…

Centos 配置JDK和Tomcat(新手版)

Centos 配置JDK和Tomcat&#xff08;新手版&#xff09; 1、安装JDK 如果原环境有jdk则需要卸载。 先用命令查看 rpm -qa|grep java 如果有jdk则需要卸载rpm -e --nodeps java-1.7.0-openjdk-1.7.0.191-2.6.15.5.el7.x86_64rpm -e --nodeps java-1.8.0-openjdk-…

ClickHouse初体验

1.clickHouse是啥&#xff1f; ClickHouse 是俄罗斯的 Yandex 于 2016 年开源的列式存储数据库(DBMS)&#xff0c;使用 C语言编写&#xff0c;主要用于在线分析处理查询(OLAP)&#xff0c;能够使用SQL查询实时生成分析数据报告 2.clickHouse的特点 2.1列式存储 对于列的聚合&…

web--文件下载,文件删除,文件读取

文件下载 看下载的地址 r不为空&#xff0c;所以传入donwload 下面的都能下载 实例 这样就会尝试下载1.zip 下载上一个目录的文件 包含了很多&#xff0c;里面可能就有配置文件 就是看到这种直接放文件上去 任意文件读取 得搜索特定函数&#xff0c;然后去源码找 找到调用的地…

软考 系统架构设计师系列知识点之云原生架构设计理论与实践(8)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之云原生架构设计理论与实践&#xff08;7&#xff09; 所属章节&#xff1a; 第14章. 云原生架构设计理论与实践 第2节 云原生架构内涵 14.2 云原生架构内涵 关于云原生的定义有众多版本&#xff0c;对于云原生架构的…

JAVA的控制语句

控制语句 分为顺序、选择和循环 顺序结构 先执行a&#xff0c;再执行b 条件判断结构 如果......则....... 循环结构 如果.....则重复执行 条件判断结构&#xff08;选择结构&#xff09; if单分支结构 语法结构&#xff1a; if(布尔表达式){ 语句块 } 注&#xff…

极简wordpress网站模板

Pithy设计师wordpress网站模板 精练简洁的wordpress模板&#xff0c;设计师或设计工作室展示型网站模板。 https://www.jianzhanpress.com/?p6329

11.Notepad++

文章目录 一、下载和安装设置练习 以前在记事本上写的代码看上去有点累&#xff0c;因为所有的单词看上去都是黑色的&#xff0c;并且当代码出现问题后&#xff0c;它提示第三行&#xff0c;我们还需要一行一行去数。这些问题都可以由一个高级记事本&#xff1a; Notepad 来解…

Ceph——部署

Ceph简介 Ceph是一款开源的 SDS 分布式存储&#xff0c;它具备极高的可用性、扩展性和易用性&#xff0c;可用于存 储海量数据 Ceph的存储节点可部署在通用服务器上&#xff0c;这些服务器的 CPU 可以是 x86 架构的&#xff0c;也可以 是 ARM 架构的。 Ceph 存储节点之间相互…

深入探讨分布式ID生成方案

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

【Functional Affordances】如何确认可抓取的区域?(前传)

文章目录 1. 【Meta AI】Emerging Properties in Self-Supervised Vision Transformers2. 【Meta AI】DINOv2: Learning Robust Visual Features without Supervision3. 【NeurIPS 2023】Diffusion Hyperfeatures: Searching Through Time and Space for Semantic Corresponden…

网安学习笔记-day9,DNS服务器介绍

文章目录 DNS服务器部署域名介绍及分类DNS解析解析过程1.递归查询2.迭代查询 DNS服务器部署准备阶段安装DNS服务 部署过程在另一台虚拟机查看是否能解析到baidu.com的地址测试解析 转发器 扩展命令 DNS服务器部署 DNS(Domain Name System) 域名介绍及分类 常用的www.baidu.c…
最新文章