8.21 QT

1.思维导图

服务器端

头文件

复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>//服务器类
#include <QMessageBox>
#include <QDebug>
#include <QList>
#include <QTcpSocket>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

public slots:
    void newConnection_slot();
    void readyRead_slot();

private slots:
    void on_start_btn_clicked();

private:
    Ui::Widget *ui;

    //实例化一个服务器只针对象
    QTcpServer *server;

    QList <QTcpSocket *> socketList;
};
#endif // WIDGET_H

源文件

复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    , server(new QTcpServer(this))//给服务器指针对象实例空间
{
    ui->setupUi(this);
}

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

//newConnection信号对应的槽函数实现
void Widget::newConnection_slot()
{
    qDebug() << "有新的客户端连接。。";

    //使用nextPaddingConnection() 获取最新连接客户端的套接字
    QTcpSocket *s = server->nextPendingConnection();

    //将客户端放入容器中
    socketList.push_back(s);

    //程序运行至此,说明客户端和服务器成功建立了连接,
    //就可以将该信号连接到自定义的槽函数中,读取发来的数据
    connect(s,&QTcpSocket::readyRead,this,&Widget::readyRead_slot);
}

//readyRead()信号对应的槽函数
void Widget::readyRead_slot()
{
    //读取客户端发来的数据

    //遍历客户端容器,移除无效客户端
    for (int i=0;i<socketList.count();i++)
    {
        //判断客户端和服务器的连接状态
        //SocketState state() const;
        //客户端和服务器未连接的枚举值是0
        if(socketList.at(i)->state() == 0)
        {
            //移除无效客户端
            socketList.removeAt(i);
        }
    }
    //遍历所有在线的客户端,找出待读数据的客户端
    for (int i = 0; i<socketList.count(); i++)
    {
        //判断哪个客户端有数据待读
        if(socketList.at(i)->bytesAvailable() !=0)
        {
            //读取数据
            QByteArray msg = socketList.at(i)->readAll();

            //将读取到的数据放入ui界面上
            ui->listWidget->addItem(QString::fromLocal8Bit(msg));

            //将数据广播给所有客户端
            for (int j=0;j<socketList.count();j++)
            {
                socketList.at(j)->write(msg);
            }
        }
    }
}

//启动服务器按钮对应的槽函数
void Widget::on_start_btn_clicked()
{
    //获取ui界面上的端口号
    quint16 port = ui->portEdit->text().toUInt();//将字符串转换为整型

    //服务器设置监听
    //bool listen(const QHostAddress &address = QHostAddress::Any,quint16 port=0);
    //参数1:监听的主机
    //参数2:监听的端口号
    //返回值:监听成功返回true  否则false
    if(server->listen(QHostAddress::Any,port))
    {
        //监听成功
        QMessageBox::information(this,"","启动服务器成功!");
    }
    else
    {
        //监听失败
        QMessageBox::information(this,"","启动服务器失败!");
        return;
    }
    //此时如果有客户端发来连接请求,那么服务器就会自动发射一个newConnection()信号
    //将该信号连接到自定义的槽函数中,处理逻辑代码
    connect(server,&QTcpServer::newConnection,this,&Widget::newConnection_slot);


}

客户端

头文件

复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpSocket>
#include <QMessageBox>
#include <QVBoxLayout>


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_connectbtn_clicked();
    void on_sendbtn_clicked();

    void on_breakbtn_clicked();

public slots:
    void connected_slot();
    void readyRead_slot();
    void disconnected_slot();

private:
    Ui::Widget *ui;

    QTcpSocket *socket;

    //
    QString userName;
};
#endif // WIDGET_H

源文件

复制代码
#include "widget.h"
#include "ui_widget.h"

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

    //初始化界面
    ui->msgEdit->setEnabled(false);
    ui->sendbtn->setEnabled(false);
    ui->breakbtn->setEnabled(false);

    //如果成功连接到服务器,那么客户端就会自动发射一个connected()信号
    //我们就可以将该信号连接到自定义的槽函数中处理逻辑代码,由于只需要连接一次,所以连接函数写在构造函数中
    connect(socket, &QTcpSocket::connected, this, &Widget::connected_slot);

    //程序运行至此,说明客户端成功与服务建立连接,如果服务器发来数据,那么客户端就会自动发射一个readyRead()信号
    //我们就可以将该信号连接到自定义的槽函数,读取数据。由于只需连接一次,所以连接函数写在构造函数中
    connect(socket, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);

    //如果成功断开与服务器的连接,那么客户端就会自动发射一个disconnected的信号
    //我们就可以将该信号连接到自定义的槽函数,。由于只需连接一次,所以连接函数写在构造函数中
    connect(socket,&QTcpSocket::disconnected,this,&Widget::disconnected_slot);
}

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

//readyRead()信号对应的槽函数
void Widget::readyRead_slot()
{
    static int row=0;

    //读取服务器发来的数据
    QByteArray msg = socket->readAll();

    //拆分出用户名
        QStringList list = (QString::fromLocal8Bit(msg)).split(":");

        //将数据放入ui界面上
        ui->listWidget->addItem(QString::fromLocal8Bit(msg));

        //根据用户名设置显示位置
        if(list[0]==userName)
        {
            //是本人的消息    靠右显示
            ui->listWidget->item(row)->setTextAlignment(Qt::AlignRight);
        }else
        {
            //不是本人的消息    靠左显示
            ui->listWidget->item(row)->setTextAlignment(Qt::AlignLeft);
        }

        if(list[1]=="离开聊天室"||list[1]=="进入聊天室")
        {
            //居中显示
            ui->listWidget->item(row)->setTextAlignment(Qt::AlignCenter);
        }
   row++;
}

//connected()信号对应的槽函数
void Widget::connected_slot()
{
    userName = ui->userNameEdit->text();
    QString msg = userName + ":进入聊天室";

    //将信息发送服务器
    socket->write(msg.toLocal8Bit());

    //连接服务器成功
    QMessageBox::information(this,"","连接成功!");

    //组件可用的相关设置
    ui->msgEdit->setEnabled(true);
    ui->sendbtn->setEnabled(true);
    ui->breakbtn->setEnabled(true);

    ui->userNameEdit->setEnabled(false);
    ui->ipEdit->setEnabled(false);
    ui->portEdit->setEnabled(false);
    ui->connectbtn->setEnabled(false);

    //程序运行至此,说明客户端成功与服务建立连接,如果服务器发来数据,那么客户端就会自动发射一个readyRead()信号
    //我们就可以将该信号连接到自定义的槽函数,读取数据。由于只需连接一次,所以连接函数写在构造函数中
}

//disconnected()信号对应的槽函数
void Widget::disconnected_slot()
{
    //组件可用的相关设置
    ui->msgEdit->setEnabled(false);
    ui->sendbtn->setEnabled(false);
    ui->breakbtn->setEnabled(false);

    ui->userNameEdit->setEnabled(true);
    ui->ipEdit->setEnabled(true);
    ui->portEdit->setEnabled(true);
    ui->connectbtn->setEnabled(true);

}

//发送按钮对应的槽函数
void Widget::on_sendbtn_clicked()
{
    //获取ui界面的信息
    QString msg = ui->msgEdit->text();

    msg = userName + ":" + msg;

    //发送给服务器
    socket->write(msg.toLocal8Bit());

    //清空行编辑器
    ui->msgEdit->clear();
}

//连接服务器按钮对应的槽函数
void Widget::on_connectbtn_clicked()
{
    //获取ui界面上的IP和端口号
    QString ip = ui->ipEdit->text();
    quint16 port = ui->portEdit->text().toUInt();

    //让客户端连接服务器
    //virtual void connectToHost(const QHostAddress &address, quint16 port, OpenMode mode = ReadWrite);
    //参数1:服务器的ip地址
    //参数2:端口号
    socket->connectToHost(ip,port);

    //如果成功连接到服务器,那么客户端就会自动发射一个connected()信号
    //将该信号连接到自定义的槽函数,书写逻辑代码。由于只需要连接一次,所以连接函数写在构造函数中

}

//断开连接按钮对应的槽函数
void Widget::on_breakbtn_clicked()
{
    QString msg = userName + ":离开聊天室";

    socket->write(msg.toLocal8Bit());

    //断开与服务器的连接
    //virtual void disconnectFromHost();
    socket->disconnectFromHost();

    //如果成功断开与服务器的连接,那么客户端就会自动发射一个disconnected的信号
    //我们就可以将该信号连接到自定义的槽函数,。由于只需连接一次,所以连接函数写在构造函数中
}
相关推荐
Larry_Yanan5 小时前
Qt多进程(三)QLocalSocket
开发语言·c++·qt·ui
刺客xs12 小时前
Qt ----- QT线程
开发语言·qt
SunkingYang15 小时前
QT程序如何将事件和消息发送给MFC程序,MFC程序如何接收消息和事件
qt·mfc·消息·事件·通信·通讯·传递
凯子坚持 c17 小时前
Qt 5.14.0 入门框架开发全流程深度解析
开发语言·qt
深蓝海拓17 小时前
PySide6从0开始学习的笔记(十四)创建一个简单的实用UI项目
开发语言·笔记·python·qt·学习·ui·pyqt
小尧嵌入式17 小时前
Linux网络介绍网络编程和数据库
linux·运维·服务器·网络·数据库·qt·php
海涛高软18 小时前
Qt中使用QListWidget列表
开发语言·qt
010米粉01018 小时前
Qt之构建方式
qt
凯子坚持 c19 小时前
Qt 信号与槽机制深度解析
开发语言·qt
世转神风-19 小时前
qt-初步编译运行报错-When executing step “Make“-无法启动进程“make“
开发语言·qt