【QT】Day4

1> 思维导图

2> 手动完成服务器的实现,并具体程序要注释清楚

widget.h

复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>   //服务器类
#include <QTcpSocket>   //客户端类
#include <QMessageBox>  //对话框类
#include <QList>        //链表容器,用于存放客户端套接字
#include <QDebug>       //信息调试类

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_startBtn_clicked();
    void newConnection_slot();
    void readyRead_slot();

private:
    Ui::Widget *ui;

    //定义服务器指针
    QTcpServer *server;

    //定义客户端容器
    QList<QTcpSocket*> socketList;
};
#endif // WIDGET_H

widget.cpp

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //给服务器指针实例化空间
    server = new QTcpServer(this);  //创建一个服务器
}

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

//"启动服务器" 对应的槽函数
void Widget::on_startBtn_clicked()
{
    //获取ui界面上的端口号
    quint16 port = ui->portEdit->text().toUInt();

    //将服务器设置成监听状态
    //函数原型: bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
        //功能:监听客户端发来的连接请求
        //参数1:要监听的主机地址,Any表示监听任意主机地址,也可以给定指定主机地址
        //参数2:提供的端口号,如果是0:表示让系统自动分配端口号
        //返回值:bool,成功监听返回true,失败返回false
    if(server->listen(QHostAddress::Any,port) == true)
    {
        QMessageBox::information(this,"","服务器启动成功");
    }
    else
    {
        QMessageBox::information(this,"","服务器启动失败");
    }

    //此时服务器已经进入监听状态,如果有客户端发送连接请求,该服务器就会自动发射一个newConnection信号
    //那么我们可以将该信号连接到自定义的槽函数中处理新连接的套接字
    connect(server,&QTcpServer::newConnection,this,&Widget::newConnection_slot);
}

//处理newConnection信号的槽函数
void Widget::newConnection_slot()
{
    qDebug() << "有客户端连接了";

    //获取最新连接的客户端套接字
    //函数原型:  virtual QTcpSocket *nextPendingConnection();
        //功能:获取最新连接客户端的套接字
        //参数:无
        //返回值:套接字指针
    QTcpSocket *s = server->nextPendingConnection(); //获取套接字

    //将套接字放入到客户端容器中
    socketList.push_back(s);    //尾插

    //此时,客户端与服务器已经建立起来连接,如果有客户端向服务器发来数据,客户端会自动发射一个readyRead信号
    //我们可以在该信号对应的槽函数中,读取客户端中的数据
    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);  //将下标为i的套接字从链表中移除
        }
    }

    //遍历客户端套接字,寻找是哪个客户端有数据待读
    for(int i=0;i<socketList.count();i++)
    {
        //函数原型:qint64 bytesAvailable() const override;
            //功能:求出当前套接字中待读数据的个数
            //参数:无
            //返回值:待读数据的个数
        if(socketList.at(i)->bytesAvailable() != 0)
        {
            //函数原型:QByteArray readAll()
                //功能:读取当前套接字中的数据
                //返回值:QByteArray读取下来的数据
            QByteArray msg = socketList.at(i)->readAll();

            //将数据展示到ui界面上
            ui->msgWidget->addItem(QString::fromLocal8Bit(msg));

            //将数据发送给所有客户端
            for(int j=0;j<socketList.count();j++)
            {
                //将数据写入到所有客户端套接字中
                socketList.at(j) ->write(msg);
            }
        }
    }
}
相关推荐
用户805533698031 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner1 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz6 天前
QML Hello World 入门示例
qt
xcyxiner9 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner10 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner10 天前
DicomViewer (添加模型类)3
qt
xcyxiner11 天前
DicomViewer (目录调整) 2
qt
xcyxiner11 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00613 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术13 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript