Qt网络编程-简易版TcpServer入门Demo(2)

11 篇文章 12 订阅

Qt网络编程-简易版TcpServer入门Demo(2)🦏

更多精彩内容
👉个人内容分类汇总 👈
简易版
👉Qt网络编程-简易版TcpClient入门Demo(1)👈
👉Qt网络编程-简易版TcpServer入门Demo(2)👈
👉Qt网络编程-简易版UDP单播通信入门Demo(3)👈
👉Qt网络编程-简易版UDP单播通信入门Demo(4)👈
👉Qt网络编程-简易版UDP组播通信入门Demo(5)👈
进阶版
👉Qt网络编程-TcpClient入门Demo(1)👈
👉Qt网络编程-TcpServer入门Demo(2)👈

1、概述🐅

使用QTcpServer实现TCP Server,十分简易的入门Demo

第一,绝对不意气用事;

第二,绝对不放过任何一个注释;

第三,绝对保证代码的简洁明了。🤘

为了便于学习,在这个Demo里会尽可能简单的实现TCP服务端功能,尽可能少的引入其它功能,只保留了基本功能,所以可能会有一些bug。

实现功能:

  • 监听1个Tcp客户端连接功能,多余的连接自动断开;
  • 数据接收功能;
  • 数据发送功能

2、TCP服务端流程图🐴

  • TCP服务端除了监听连接部分外,其它的和TCP客户端基本一样。
    在这里插入图片描述

3、 关键信号🐕

信号说明
newConnectionQTcpServer监听到新的客户端连接
disconnectedQTcpSocket断开连接后发出此信号
readyReadQTcpSocket有可读数据时发出此信号

4、 关键函数 🐶

函数名说明
isListening判断是否正在监听连接
listen绑定服务器侦听地址和端口上的传入连接。如果端口为0,则会自动选择一个端口。(相当于bind + listen )
nextPendingConnection返回已连接的QTcpSocket,如果有已连接的QTcpSocket没调用这个函数返回,将在QTcpServer释放时会自动统一释放(所以存在一定的内存泄漏问题)
close关闭服务器。 服务器将不再监听传入连接

5、主要代码🦍

  • 注意:.pro文件里添加QT += network,否则编译失败。

  • .h文件

    /******************************************************************************
     * @文件名     simpletcpserver.h
     * @功能       简易的TCP服务端Demo,只保留接听TCP(1个)客户端连接/断开、 数据发送、接收功能
     *
     * @开发者     mhf
     * @邮箱       1603291350@qq.com
     * @时间       2022/04/17
     * @备注
     *****************************************************************************/
    #ifndef SIMPLETCPSERVER_H
    #define SIMPLETCPSERVER_H
    
    #include <QWidget>
    #include <QTcpServer>
    
    namespace Ui {
    class SimpleTcpServer;
    }
    
    class SimpleTcpServer : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit SimpleTcpServer(QWidget *parent = nullptr);
        ~SimpleTcpServer();
    
    private slots:
        void on_newConnection();
        void on_disconnected();
        void on_readyRead();
        void on_but_connect_clicked();
    
        void on_but_send_clicked();
    
    private:
        Ui::SimpleTcpServer *ui;
        QTcpServer* m_server = nullptr;        // TCP服务端对象
        QTcpSocket* m_client = nullptr;        // 连接成功的客户端
    };
    
    #endif // SIMPLETCPSERVER_H
    
    
  • .cpp文件

    #include "simpletcpserver.h"
    #include "ui_simpletcpserver.h"
    
    #include <qtcpsocket.h>
    
    SimpleTcpServer::SimpleTcpServer(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::SimpleTcpServer)
    {
        ui->setupUi(this);
    
        this->setWindowTitle("简易版本TCP 服务端Demo");
    
        m_server = new QTcpServer(this);
        connect(m_server, &QTcpServer::newConnection, this, &SimpleTcpServer::on_newConnection);    // 监听新的客户端连接
    }
    
    SimpleTcpServer::~SimpleTcpServer()
    {
        delete ui;
    }
    
    
    void SimpleTcpServer::on_but_connect_clicked()
    {
        if(!m_server->isListening())          // 判断是否正在监听连接
        {
            // 告诉服务器侦听地址和端口上的传入连接。如果端口为0,则会自动选择一个端口。
            // 如果地址是QHostAddress::Any,服务器将监听所有网络接口。
            bool ret = m_server->listen(QHostAddress::Any, ui->spin_localPort->value());
            if(ret)
            {
                ui->but_connect->setText("停止");
            }
            else
            {
                qDebug() << QString("tcpServer绑定监听IP、端口失败:%1 %2").arg(m_server->errorString()).arg(m_server->serverError());
            }
        }
        else
        {
            m_client->abort();
            m_server->close();
            ui->but_connect->setText("开始监听");
        }
    }
    
    /**
     * @brief 如果有新的TCP客户端发起连接,则会在这个函数中返回连接成功的QTcpSocket;
     *        这里只保留第一个连接成功的客户端,其它的自动断开连接
     */
    void SimpleTcpServer::on_newConnection()
    {
        QTcpSocket* tcpSocket = m_server->nextPendingConnection();    // 存在内存泄漏,最好使用时通过hasPendingConnections判断是否有未返回的连接
        if(tcpSocket)
        {
            if(m_client)         // 如果已经有连接的 客户端,则断开后面所有的连接
            {
                tcpSocket->deleteLater();
                return;
            }
            m_client = tcpSocket;
            connect(tcpSocket, &QTcpSocket::disconnected, this, &SimpleTcpServer::on_disconnected);        // 断开连接
            connect(tcpSocket, &QTcpSocket::readyRead, this, &SimpleTcpServer::on_readyRead);              // 接收客户端发来的数据
        }
    }
    
    /**
     * @brief 断开连接
     */
    void SimpleTcpServer::on_disconnected()
    {
        disconnect(m_client, &QTcpSocket::disconnected, this, &SimpleTcpServer::on_disconnected);          // 断开绑定的信号槽
        disconnect(m_client, &QTcpSocket::readyRead, this, &SimpleTcpServer::on_readyRead);
        //delete m_client;                // 这里不能用delete,否则在vs里会报错 0x00007FFBF870A1CE (Qt5Networkd.dll)处(位于 QMNetwork.exe 中)引发的异常: 0xC0000005: 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突。
        QTcpSocket* tcpSocket = m_client;
        m_client = nullptr;              // 先将m_client置空,因为deleteLater不会置空
        tcpSocket->deleteLater();        // 移除已经断开连接的Client(注意这里不能使用delete,否则在vs中会报错),但这种方式不会置为 空
    }
    
    /**
     * @brief 接收数据,这里和TCP Client是一样的
     */
    void SimpleTcpServer::on_readyRead()
    {
        QByteArray dataArr = m_client->readAll();        // 一次性读取缓存中所有数据
        if(dataArr.count() <= 0)   // 没有读取到数据
        {
            return;
        }
    
        ui->text_recv->append(dataArr);        // 显示读取到的数据
    }
    
    /**
     * @brief 发送数据,这里和TCP Client是一样的
     */
    void SimpleTcpServer::on_but_send_clicked()
    {
        if(!m_client) return;                                                       // 判断是否为空,如果为空则未连接
        if(m_client->state() != QAbstractSocket::ConnectedState) return;  // 判断TCP是否已连接,如果没有连接则不发送数据
    
        QString str = ui->text_send->toPlainText();         // 获取输入框的内容
        qint64 len = m_client->write(str.toUtf8());      // 发送数据,toUtf8()是为了支持发送中文,但是如果接收端编码方式不同则中文可能显示乱码
        if(len < 0)
        {
            qWarning() <<"发送失败!";
        }
    }
    
    

6、实现效果🐒

在这里插入图片描述

7、源代码🐈

gitee
github

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mahuifa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值