• Qt入门(七)——TCP传输协议(利用多线程实现多个客户机与服务器连接)


    一、服务器

    1.1 ui设计

    1.1.1 图像展示

    在这里插入图片描述

    1.1.2 类名定义

    在这里插入图片描述

    1.2 代码展示

    1.2.1 mythread.h

    #ifndef MYTHREAD_H
    #define MYTHREAD_H
    
    #include 
    #include 
    #include 
    #include 
    #include 
    
    //继承QThread这个类,
    class Mythread : public QThread
    {
        Q_OBJECT
    public:
        explicit Mythread(QTcpSocket *s);
        //线程函数(虚函数)
        void run();
    
    signals:
        void SendToWidget(QByteArray ba);
    
    public slots:
        void ClientinfoSlots();
        void ThreadSlots(QByteArray ba);
    private:
        QTcpSocket *sock;
    };
    
    #endif // MYTHREAD_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    1.2.2 widget.h

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include 
    #include 
    #include 
    #include "mythread.h"
    #define PORT 8000
    
    namespace Ui {
    class Widget;
    }
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit Widget(QWidget *parent = 0);
        ~Widget();
    private slots:
        void NewClientHandeler();
        void ClientInfiSlots();
        void ThreadSlots(QByteArray ba);
    
    private:
        Ui::Widget *ui;
        QTcpServer *Tcpserver;
        QTcpSocket *socket;
    };
    
    #endif // WIDGET_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    1.2.3 mian.cpp

    #include "widget.h"
    #include 
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Widget w;
        w.show();
    
        return a.exec();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    1.2.4 mythread.cpp

    #include "mythread.h"
    
    Mythread::Mythread(QTcpSocket *s)
    {
        sock = s;
    }
    
    void Mythread::run()
    {
        connect(sock,&QTcpSocket::readyRead,this,&Mythread::ClientinfoSlots);
    }
    
    void Mythread::ClientinfoSlots()
    {
        QByteArray ba = sock->readAll();
        emit SendToWidget(ba);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    1.2.5 widget.cpp

    #include "widget.h"
    #include "ui_widget.h"
    
    Widget::Widget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::Widget)
    {
        ui->setupUi(this);
        Tcpserver = new QTcpServer;
        socket = new QTcpSocket;
        //监听任何IPv4地址,PORT是写死8000的
        Tcpserver->listen(QHostAddress::AnyIPv4,PORT);
        //客户端发起连接,server会发出信号
        connect(Tcpserver,&QTcpServer::newConnection,this,&Widget::NewClientHandeler);
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    
    void Widget::NewClientHandeler()
    {
        //建立tcp连接
        socket = Tcpserver->nextPendingConnection();//socket就包含了这个客户端的所有消息
        socket->peerPort(); //对端(客户端)的端口
        socket->peerAddress(); //对端(客户端)的ip地址
        //进行显示
        ui->IplineEdit->setText(socket->peerAddress().toString());
        ui->PortlineEdit->setText(QString::number(socket->peerPort()));
        //判断是发信息的,不是发起连接的,之后进行槽函数处理
        //connect(socket,&QTcpSocket::readyRead,this,&Widget::ClientInfiSlots);
        //创建新线程(new 一个对象)
        Mythread *t = new Mythread(socket);
        t->start();
        connect(t,&Mythread::SendToWidget,this,&Widget::ThreadSlots);
    }
    
    void Widget::ClientInfiSlots()
    {
        ui->MesglineEdit->setText(QString(socket->readAll()));
    }
    
    void Widget::ThreadSlots(QByteArray ba)
    {
        ui->MesglineEdit->setText(QString(ba));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    二、客户端

    2.1 ui设计

    2.1.1 图像展示

    在这里插入图片描述
    在这里插入图片描述

    2.1.2 类名定义

    在这里插入图片描述
    在这里插入图片描述

    2.2 代码展示

    2.2.1 chat.h

    #ifndef CHAT_H
    #define CHAT_H
    
    #include 
    #include 
    
    namespace Ui {
    class chat;
    }
    
    class chat : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit chat(QTcpSocket *s,QWidget *parent = 0);
        ~chat();
    
    private slots:
        void on_SendButton_clicked();
    
        void on_ClearButton_clicked();
    
        void on_CloseButton_clicked();
    
    private:
        Ui::chat *ui;
        QTcpSocket *sock;
    };
    
    #endif // CHAT_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    2.2.2 widget.h

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include 
    #include 
    #include 
    #include 
    #include "chat.h"
    
    namespace Ui {
    class Widget;
    }
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit Widget(QWidget *parent = 0);
        ~Widget();
    
    private slots:
        void on_ConnectButton_clicked();
    
        void on_CloseButton_clicked();
    
    private:
        Ui::Widget *ui;
        QTcpSocket *sock;
    };
    
    #endif // WIDGET_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    2.2.3 chat.cpp

    #include "chat.h"
    #include "ui_chat.h"
    
    chat::chat(QTcpSocket *s,QWidget *parent) :
        QWidget(parent),
        ui(new Ui::chat)
    {
        ui->setupUi(this);
        sock = s;
    }
    
    chat::~chat()
    {
        delete ui;
    }
    
    void chat::on_SendButton_clicked()
    {
        QByteArray ba;
        //将文本框内的内容转到二进制数组里面
        ba.append(ui->MesglineEdit->text());
        //写的是二进制
        sock->write(ba);
    }
    
    void chat::on_ClearButton_clicked()
    {
        ui->MesglineEdit->clear();
    }
    
    void chat::on_CloseButton_clicked()
    {
        this->close();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    2.2.4 main.cpp

    #include "widget.h"
    #include 
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Widget w;
        w.show();
    
        return a.exec();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.2.5 widget.cpp

    #include "widget.h"
    #include "ui_widget.h"
    
    Widget::Widget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::Widget)
    {
        ui->setupUi(this);
        sock = new QTcpSocket; //创建套接字对象
        //连接成功
        connect(sock,&QTcpSocket::connected,[this](){
            QMessageBox::information(this,"连接提示","连接成功");
            //连接成功将隐藏当前窗口,进入chat页面
            this->hide();
            chat *c = new chat(sock);
            c->show();
        });
        //连接失败
        connect(sock,&QTcpSocket::disconnected,[this](){
            QMessageBox::warning(this,"连接提示","网络断开");
        });
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    
    void Widget::on_ConnectButton_clicked()
    {
        //连接ip地址和窗口
        QString Ipaddr = ui->iplineEdit->text();
        QString Port = ui->PortlineEdit->text();
        //连接服务器
        sock->connectToHost(QHostAddress(Ipaddr),Port.toShort());
    }
    
    void Widget::on_CloseButton_clicked()
    {
        this->close();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    三、最终成果

    请添加图片描述

    四、对于线程信号的理解

    线程这个逻辑流程,就是首先子客户端建立连接,之后将信号传入线程函数,发射信号,传入服务器进程处理

  • 相关阅读:
    【C语言】符号的深度理解
    习题7-1 选择法排序
    ZoomIt最简单方便的屏幕画图工具操作手册
    java计算机毕业设计科院垃圾分类系统源码+数据库+系统+lw文档+mybatis+运行部署
    集美大学第九届程序设计竞赛 L.序列 逆序对
    Virtualbox中对SD卡进行格式化和分区
    IllegalStateException: FragmentManager is already executing transactions
    主流电商平台价格如何高频监测
    如何在不结束tcpdump的情况下复制完整的pcap
    Windows服务器如何防止黑客入侵的安全设置
  • 原文地址:https://blog.csdn.net/m0_52592798/article/details/126282214