【Qt网络编程】Tcp多线程并发服务器和客户端通信

news/2024/9/20 7:38:24/ 标签: c++, qt, 服务器, 网络

目录

一、编写思路

1、服务器

(1)总体思路widget.c(主线程)

(2)详细流程widget.c(主线程)

(1)总体思路chat_thread.c(处理聊天逻辑线程)

(2)详细流程chat_thread.h(处理聊天逻辑线程)

2、客户端

(1)总体思路widget.c(主线程)

(2)详细思路widget.c(主线程)

(1)总体思路chat_thread.c(处理聊天逻辑线程)

(2)详细流程chat_thread.c(处理聊天逻辑线程)

二、实现效果

1、服务器

2、客户端


完整代码请到指定链接下载:Qt网络编程-Tcp多线程并发服务器和客户端通信: 【Qt网络编程】Tcp多线程并发服务器和客户端通信

一、编写思路

1、服务器

(1)总体思路widget.c(主线程)

  1. 初始化界面

    创建窗口、输入框、按钮等基本UI元素。

  2. 创建服务器对象

    实现 My_tcp_server 并监听客户端连接。

  3. 处理新客户端连接

    当有新客户端连接时,创建新的 Chat_thread 线程来处理通信。

  4. 绑定信号槽

    确保主线程与客户端处理线程间的信号槽连接,使用 Qt::QueuedConnection 处理跨线程通信。

  5. 处理消息传递

    接收和发送消息,并在界面上更新显示。

  6. 服务器启动与关闭

    通过按钮控制服务器的启动和关闭,管理所有客户端线程的安全退出。

(2)详细流程widget.c(主线程)

  1. 创建 Qt 界面及设置窗口属性: 首先通过 ui->setupUi(this); 来初始化用户界面,并设置窗口标题、大小等基本属性。这是 Qt 项目的常见步骤,通过 .ui 文件生成的类进行界面管理。

    Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)  // 初始化UI对象
    {ui->setupUi(this);  // 设置UI界面this->setWindowTitle("--服务器--");  // 设置窗口标题this->resize(1024, 960);  // 设置窗口大小
    ​ui->le_ip->setText("127.0.0.1");ui->le_port->setText("9999");
    }

  2. 初始化服务器对象 My_tcp_server 并处理客户端连接

    • 创建 tcp_server 对象以处理客户端的连接。

    • 使用 connect 函数连接 tcp_servernew_descriptor 信号和匿名槽函数,确保一旦有新客户端连接,便创建一个 Chat_thread 来处理该客户端。

    this->tcp_server = new My_tcp_server(this);
    ​
    connect(tcp_server, &My_tcp_server::new_descriptor, this, [=](qintptr socketDescriptor){QMessageBox::information(this, "提示", "新的客户端连接!", QMessageBox::Ok, QMessageBox::Information);
    ​ui->btn_send->setEnabled(true);  // 启用“发送消息”按钮
    ​// 创建新线程处理客户端Chat_thread *chat_thread = new Chat_thread(socketDescriptor);chat_thread->moveToThread(chat_thread);  // 将线程和对象绑定到同一线程,防止冲突
    ​thread_list.append(chat_thread);// 启动线程处理客户端通信chat_thread->start();
    });
  3. 管理客户端线程 Chat_thread

    • 每当有新客户端连接时,创建一个 Chat_thread 并启动它处理客户端通信。通过 moveToThreadChat_thread 的执行线程与该对象保持一致,避免跨线程冲突。

    • 使用 connect 绑定线程中的信号(如连接断开、接收消息)和主界面槽函数,确保客户端状态能够正确显示。

    Chat_thread *chat_thread = new Chat_thread(socketDescriptor);
    chat_thread->moveToThread(chat_thread);  // 将线程与对象绑定在同一线程
    ​
    thread_list.append(chat_thread);
    ​
    // 连接信号和槽
    connect(chat_thread, &Chat_thread::break_connect, this, [=](){ui->te_receive->append(currentTime + "\n【状态】客户端断开连接...");ui->btn_send->setEnabled(false);  // 禁用“发送消息”按钮
    });
    ​
    connect(chat_thread, &Chat_thread::recv_info, this, [=](QString data){currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");ui->te_receive->append(currentTime + "form client\n    【数据】 " + data);  // 在文本框中显示消息
    });
    ​
    chat_thread->start();  // 启动线程
  4. 处理启动和关闭服务器的按钮事件

    • on_btn_connect_clicked() 处理连接按钮点击事件,启动或关闭服务器

    • 启动时,检查 IP 地址和端口的有效性,成功后开始监听客户端连接。

    • 关闭服务器时,停止监听,并确保所有已连接客户端线程安全退出。

    void Widget::on_btn_connect_clicked()
    {if (!is_server_running){// 启动服务器QString ip_address = ui->le_ip->text().trimmed();QString port_text = ui->le_port->text().trimmed();if (!tcp_server->listen(QHostAddress(ip_address), port_text.toUInt())){QMessageBox::warning(this, "warning", "服务器监听失败");return;}is_server_running = true;ui->btn_connect->setText("关闭服务器");ui->te_receive->append(currentTime + "\n【状态】服务器开始监听...");}else{// 停止服务器并关闭所有客户端线程tcp_server->close();for (Chat_thread *thread : qAsConst(thread_list)){thread->exit();thread->wait();thread->deleteLater();}thread_list.clear();is_server_running = false;ui->btn_connect->setText("创建服务器");ui->te_receive->append(currentTime + "\n【状态】服务器已停止监听...");}}
  1. 处理发送消息按钮的点击事件

    • 当点击“发送消息”按钮时,触发 send_request 信号,利用信号槽机制将输入的消息发送给客户端。需要确保主线程和子线程的信号槽通信是异步进行的(通过 Qt::QueuedConnection)。

    void Widget::on_btn_send_clicked()
    {QString data = ui->te_send->toPlainText().toUtf8();emit send_request(data);  // 发出 send_request 信号
    }

  2. 服务器监听客户端的状态和信息传递

    • 服务器通过 recv_infosend_info 信号接收客户端消息并在界面上显示。

    • 在客户端连接成功或断开时,更新界面显示状态。

    connect(chat_thread, &Chat_thread::recv_info, this, [=](QString data){currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");ui->te_receive->append(currentTime + "form client\n    【数据】 " + data);  // 显示接收的客户端数据
    });
    ​
    connect(chat_thread, &Chat_thread::send_info, this, [=](QString data){currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");ui->te_receive->append(currentTime + "to client\n    【数据】 " + data);  // 显示发送给客户端的数据
    });

(1)总体思路chat_thread.c(处理聊天逻辑线程)

  1. 构造函数

    初始化 socketDescriptor 以供后续线程使用。

  2. 线程启动与套接字初始化

    run() 函数中创建 QTcpSocket,并关联 socketDescriptor

  3. 获取客户端信息

    通过 peerAddress()peerPort() 获取客户端 IP 地址和端口号,并进行错误处理。

  4. 信号槽机制连接

    将套接字状态、接收数据、错误处理等信号连接到相应的槽函数。

  5. 处理连接状态变化

    通过 handler_client_changed() 处理客户端的连接或断开,并发出相应的信号。

  6. 处理接收消息

    receive_message() 函数中处理客户端发送的消息,并发出信号 recv_info

  7. 发送消息

    send_message() 函数中,检查连接状态并发送消息,发出 send_info 信号。

  8. 错误处理

    处理客户端连接中的错误,删除资源并退出线程。

(2)详细流程chat_thread.h(处理聊天逻辑线程)

  1. 构造函数初始化

    • Chat_thread 构造函数接受一个 socketDescriptor 参数,并将其存储为类的成员变量,以供 run() 函数中使用。注意,QTcpSocket 对象将在 run() 函数中创建,以确保在新线程中创建并使用。

    Chat_thread::Chat_thread(qintptr socketDescriptor, QObject *parent): QThread{parent}, socketDescriptor(socketDescriptor)
    {// socketDescriptor 存储为成员变量
    }
  2. 线程启动和套接字初始化

    • run() 函数中创建 QTcpSocket 对象,并通过 setSocketDescriptor() 将套接字描述符与 QTcpSocket 关联。这允许线程使用此套接字与客户端通信。

    • 如果套接字初始化失败,进行错误处理并返回。

    void Chat_thread::run()
    {// 创建 QTcpSocket 对象,用于处理与客户端的通信this->socket = new QTcpSocket();
    ​// 将套接字描述符与 QTcpSocket 关联if (!socket->setSocketDescriptor(socketDescriptor)){qDebug() << "Error: Failed to get new socketDescriptor.";return;}
    ​// 错误处理:检查是否成功获取客户端连接if (socket == nullptr){qDebug() << "Error: Failed to get new client connection.";return;  // 如果获取失败,直接返回}
    }
  3. 获取客户端信息

    • 在成功创建套接字后,获取客户端的 IP 地址和端口号。

    • 如果获取失败,进行错误处理并断开连接。

    // 获取客户端的IP地址和端口号
    QString ip_addr = socket->peerAddress().toString();
    quint16 port = socket->peerPort();
    ​
    // 错误处理:检查是否成功获取IP地址和端口号
    if (ip_addr.isEmpty() || port == 0)
    {qDebug() << "Error: Failed to get client's IP address or port.";socket->disconnectFromHost();  // 断开连接socket->deleteLater();  // 删除客户端套接字对象return;  // 如果获取失败,直接返回
    }
  4. 信号槽机制的连接

    • 连接套接字的状态改变信号 stateChanged 到槽函数 handler_client_changed,以便监控客户端连接状态的变化。

    • 连接 QTcpSocketreadyRead 信号到 receive_message 槽函数,用于处理接收数据。

    • 处理套接字错误时,连接 errorOccurred 信号到 handle_socket_error 槽函数。

    // 处理连接状态变化的槽函数
    connect(socket, &QTcpSocket::stateChanged, this, &Chat_thread::handler_client_changed);
    ​
    // 错误处理:处理客户端的异常断开情况
    connect(socket, &QTcpSocket::errorOccurred, this, &Chat_thread::handle_socket_error);
    ​
    // 处理接收数据的槽函数
    connect(socket, &QTcpSocket::readyRead, this, &Chat_thread::receive_message);

  5. 处理客户端连接状态变化

    • handler_client_changed() 槽函数中,根据客户端的连接状态(如断开、已连接)做相应处理并发出信号,通知其他部分更新状态。

    void Chat_thread::handler_client_changed(QAbstractSocket::SocketState socket_state)
    {socket = (QTcpSocket*)sender();  // 获取发信的客户端套接字if(!socket) return;
    ​switch (socket_state){case QAbstractSocket::UnconnectedState:  // 客户端断开连接emit break_connect();break;
    ​case QAbstractSocket::ConnectedState:  // 客户端已连接emit complete_connect();break;
    ​default:break;}
    }
  6. 接收消息的处理

    • receive_message() 槽函数中,通过 socket->readAll() 读取客户端发送的所有数据,并发出信号 recv_info 通知上层处理。

    void Chat_thread::receive_message()
    {if (socket){QString data = socket->readAll();  // 读取客户端发送的所有数据emit recv_info(data);  // 发出信号,通知收到消息}
    }
  7. 发送消息

    • send_message() 函数中,检查客户端是否处于连接状态,如果是则发送消息,否则输出警告信息。

    • 发送完成后,发出 send_info 信号。

    void Chat_thread::send_message(QString data)
    {if (socket->state() == QAbstractSocket::ConnectedState){socket->write(data.toUtf8());  // 发送数据}else{qDebug() << "warning:   客户端未连接,无法发送消息";  // 输出警告}
    ​emit send_info(data);  // 发出信号,通知发送消息
    }
  8. 错误处理

    • handle_socket_error() 函数中处理 QTcpSocket 的错误。如果出现错误,打印错误信息,并退出线程。

    • 删除套接字对象并退出线程事件循环。

    void Chat_thread::handle_socket_error(QAbstractSocket::SocketError socketError)
    {qDebug() << "Client connection error, error code: " << socketError;
    ​this->exit();  // 退出线程this->wait();  // 等待线程完全退出socket->deleteLater();  // 删除客户端套接字对象
    ​// 停止线程事件循环quit();
    }

2、客户端

(1)总体思路widget.c(主线程)

  1. 初始化界面

    设置窗口属性并初始化用户输入的默认值。

  2. 创建线程和通信任务对象

    实现异步通信,使用 QThread 和自定义 Chat_thread 处理服务器交互。

  3. 信号槽机制的建立

    连接 UI 和工作线程之间的信号槽,确保各操作异步处理。

  4. 线程管理

    在析构函数中确保线程安全退出,释放资源。

  5. 处理连接与断开

    通过按钮触发连接和断开操作,并更新 UI 显示。

  6. 消息传递与显示

    处理消息的发送与接收,并在 UI 界面上更新显示结果。

(2)详细思路widget.c(主线程)

  1. 初始化界面

    • 使用 ui->setupUi(this) 初始化用户界面,并设置窗口标题和窗口大小。

    • 初始化 IP 地址和端口号的默认值。

    Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), is_connected(false)  // 初始化连接状态为未连接
    {ui->setupUi(this);  // 设置UI界面this->setWindowTitle("-客户端-");  // 设置窗口标题this->resize(1024, 960);  // 设置窗口大小
    ​ui->le_ip->setText("127.0.0.1");  // 设置默认IP地址ui->le_port->setText("8888");  // 设置默认端口号
    }

  2. 创建线程和通信任务对象

    • 创建 QThread 对象以进行异步通信任务。

    • 创建 Chat_thread 对象负责与服务器进行通信操作。

    • 使用 moveToThread 将通信任务对象移到新的线程中执行,并启动该线程。

    // 创建线程对象
    thread = new QThread;
    ​
    // 创建任务对象,负责与服务器的通信
    Chat_thread *worker = new Chat_thread;
    ​
    worker->moveToThread(thread);  // 将任务对象移至线程
    thread->start();  // 启动工作线程

  3. 信号槽机制的建立

    • 使用信号槽连接 UI 和工作线程之间的交互。例如,连接服务器、发送消息、断开连接等操作通过信号槽机制进行。

    • 信号从 UI 线程发出,工作线程的槽函数接收信号并执行相关操作。

    // 信号槽连接:从UI线程发出连接信号,worker线程接收并执行连接操作
    connect(this, &Widget::connect_server, worker, &Chat_thread::start_connected);
    connect(this, &Widget::send_info, worker, &Chat_thread::start_send);
    connect(this, &Widget::quit_connect, worker, &Chat_thread::break_connected);
    ​
    // 连接断开信号槽,worker线程通知UI线程更新UI
    connect(worker, &Chat_thread::connect_cancel, this, &Widget::submit_connect_cancel);
    connect(worker, &Chat_thread::connected, this, &Widget::submit_connect_info);
    connect(worker, &Chat_thread::transfer_recv_info, this, &Widget::submit_recv_info);

  4. 管理线程的生命周期

    • 在析构函数中,确保工作线程在窗口关闭时被正确停止,并释放相关资源。

    • 如果线程正在运行,需要先请求线程退出,然后等待其完全退出后再删除。

    Widget::~Widget()
    {if (thread->isRunning()){thread->quit();  // 请求线程退出thread->wait();  // 等待线程结束}delete worker;  // 删除任务对象delete thread;  // 删除线程对象delete ui;  // 删除UI对象
    }

  5. 处理连接成功或断开连接的槽函数

    • 当客户端成功连接到服务器时,工作线程发出 connected 信号,UI 界面通过槽函数 submit_connect_info() 来更新显示状态,并启用“发送消息”按钮。

    • 断开连接时,UI 界面通过槽函数 submit_connect_cancel() 来禁用“发送消息”按钮,并更新状态显示。

    // 连接成功时的槽函数,更新UI显示信息
    void Widget::submit_connect_info()
    {currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");ui->te_receive->append(currentTime + "\n【状态】已成功连接到服务器");ui->btn_connect->setText("断开服务器");ui->btn_send->setEnabled(true);   // 启用发送按钮is_connected = true;
    }
    ​
    // 断开连接时的槽函数,更新UI显示信息
    void Widget::submit_connect_cancel()
    {is_connected = false;
    }

  6. 处理消息的发送与接收

    • 当用户点击“发送消息”按钮时,获取文本框中的消息,发出 send_info 信号,将消息发送到服务器

    • 当从服务器接收到消息时,工作线程发出 transfer_recv_info 信号,UI 界面更新显示接收到的消息。

    // 当用户点击发送按钮时,读取输入框中的内容并发送给服务器
    void Widget::on_btn_send_clicked()
    {currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");QString message = ui->te_send->toPlainText().toUtf8();  // 获取用户输入的消息ui->te_receive->append(currentTime + " to server\n    【数据】" + message + "\n");emit send_info(message);  // 发出信号,通知工作线程发送消息
    }
    ​
    // 当接收到服务器发送的消息时,更新UI显示接收到的消息
    void Widget::submit_recv_info(QString message)
    {currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");ui->te_receive->append(currentTime + " form server\n    【数据】" + message + "\n");  // 显示服务器的消息
    }

  7. 处理连接与断开的按钮事件

    • 当点击“连接”按钮时,获取 IP 地址和端口号,检查输入的有效性后发出 connect_server 信号,通知工作线程与服务器建立连接。

    • 当点击“断开服务器”按钮时,发出 quit_connect 信号,通知工作线程断开连接。

    // 当用户点击"连接"按钮时触发该槽函数
    void Widget::on_btn_connect_clicked()
    {if (!is_connected){QString ip_address = ui->le_ip->text().trimmed();QString port_text = ui->le_port->text().trimmed();
    ​QHostAddress address;if (!address.setAddress(ip_address))  // 检查IP地址的有效性{QMessageBox::warning(this, "warning", "无效的IP地址,请重新输入!");return;}
    ​bool ok;unsigned int port = port_text.toUInt(&ok);if (!ok || port == 0 || port > 65535)  // 检查端口号的有效性{QMessageBox::warning(this, "warning", "无效的端口号,请输入1到65535之间的数值!");return;}
    ​emit connect_server(ip_address, port);  // 发出连接服务器的信号}else{currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");ui->te_receive->append(currentTime + "\n【状态】已断开与服务器的连接");ui->btn_send->setEnabled(false);  // 禁用发送按钮is_connected = false;emit quit_connect();  // 发出断开连接的信号}
    }

(1)总体思路chat_thread.c(处理聊天逻辑线程)

  1. 构造函数

    初始化 Chat_thread 对象。

  2. 接收消息

    通过 readyRead 信号槽接收服务器发送的数据,并将其转发给主线程。

  3. 处理连接状态变化

    监控与服务器的连接状态,并打印调试信息。

  4. 断开连接

    关闭套接字连接并释放资源,发出连接断开信号。

  5. 启动连接

    通过指定的 IP 和端口号连接服务器,并处理连接成功、失败、断开、接收数据等事件。

  6. 发送消息

    检查连接状态并发送消息。如果未连接,则发出未连接信号。

(2)详细流程chat_thread.c(处理聊天逻辑线程)

  1. 构造函数

    • 构造函数 Chat_thread::Chat_thread(QObject *parent) 初始化 Chat_thread 对象。在这个阶段不需要任何复杂的逻辑,主要是确保对象正常创建。

    Chat_thread::Chat_thread(QObject *parent): QObject{parent}
    {}

  2. 接收消息处理

    • receive_message() 是一个槽函数,用于接收从服务器发送的数据。当 QTcpSocket 对象有数据可读取时,信号 readyRead 会被触发,调用此槽函数。读取数据后,通过 transfer_recv_info 信号将接收到的消息发送出去。

    void Chat_thread::receive_message()
    {QString message = socket->readAll();  // 从服务器读取数据emit transfer_recv_info(message);  // 发出信号,通知接收到的数据
    }

  3. 处理连接状态变化

    • state_changed() 函数是一个槽函数,用于处理客户端与服务器的连接状态变化。根据不同的 QAbstractSocket::SocketState 枚举值,打印调试信息并处理相应状态的变化。

    void Chat_thread::state_changed(QAbstractSocket::SocketState socketstate)
    {QString stateStr;  // 用于保存状态的字符串switch (socketstate){case QAbstractSocket::UnconnectedState:qDebug()<< "\n【状态】与服务器断开连接...";stateStr = "UnconnectedState";break;
    ​case QAbstractSocket::ConnectedState:stateStr = "ConnectedState";qDebug()<< "【状态】与服务器建立连接...";break;
    ​case QAbstractSocket::HostLookupState:stateStr = "HostLookupState";qDebug()<< "【状态】正在查找主机...";break;
    ​case QAbstractSocket::ConnectingState:stateStr = "ConnectingState";qDebug()<< "【状态】正在连接服务器...";break;
    ​case QAbstractSocket::ClosingState:stateStr = "ClosingState";qDebug()<< "【状态】正在关闭连接...";break;
    ​default:stateStr = "UnknownState";qDebug()<< "未知的错误, 当前状态: " + stateStr;break;}
    }

  4. 断开连接处理

    • break_connected() 用于处理断开与服务器的连接。当套接字连接断开时,关闭并释放资源,并发出 connect_cancel 信号通知主线程。

    void Chat_thread::break_connected()
    {socket->close();  // 关闭套接字socket->deleteLater();  // 延迟删除套接字,释放资源emit connect_cancel();  // 发出连接断开信号
    }

  5. 开始连接服务器

    • start_connected() 用于发起连接服务器的请求。创建 QTcpSocket 对象并尝试连接到指定的 IP 和端口。连接成功、失败、断开、接收数据等事件都会通过信号槽机制进行处理。

    void Chat_thread::start_connected(QString IP, unsigned short PORT)
    {socket = new QTcpSocket;  // 创建套接字对象
    ​socket->connectToHost(QHostAddress(IP), PORT);  // 连接到服务器
    ​// 连接成功时,发送 connected 信号通知主线程上传消息connect(socket, &QTcpSocket::connected, this, &Chat_thread::connected);
    ​// 连接失败时处理connect(socket, &QTcpSocket::errorOccurred, this, [=](QAbstractSocket::SocketError socketError){qDebug() << "连接失败";QMessageBox::critical(nullptr, "连接失败", "连接失败,错误代码:" + QString::number(socketError));});
    ​// 连接断开时处理connect(socket, &QTcpSocket::disconnected, this, &Chat_thread::break_connected);
    ​// 监听数据接收connect(socket, &QTcpSocket::readyRead, this, &Chat_thread::receive_message);
    }

  6. 发送消息

    • start_send() 用于发送消息到服务器。首先检查套接字是否处于连接状态,如果已连接,则发送消息。如果未连接,则发出 not_connected 信号。

    void Chat_thread::start_send(QString message)
    {if (socket && socket->state() == QAbstractSocket::ConnectedState){socket->write(message.toUtf8());  // 发送消息}else{emit not_connected();  // 如果未连接,发出未连接信号}
    }

二、实现效果

1、服务器

2、客户端


http://www.ppmy.cn/news/1527924.html

相关文章

stable diffusion 神经网络插件 controlnet 的安装,很详细

stable diffusion 神经网络插件 controlnet 的安装&#xff0c;很详细 一、前言二、下载1、方式一2、方式二 一、前言 学到 stable diffusion 的 controlnet 插件&#xff0c;安装也略微曲折&#xff0c;这里做个记录。 下载前保证 github 能正常访问。 二、下载 1、方式一…

golang学习笔记30——golang 中代码仓库的 h1 和 go.mod h1 不一致的修正方法

推荐学习文档 golang应用级os框架&#xff0c;欢迎stargolang应用级os框架使用案例&#xff0c;欢迎star案例&#xff1a;基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识&#xff0c;这里有免费的golang学习笔…

易语言源码用键盘按键代替小键盘写法教程

相信大家都有遇到过一些难题 比方说想用一些软件 但是发现一些软件需要有小键盘的用户才能使用 那么这样就对于一些无小键盘用户造成了困扰&#xff01; 今天就给大家分享一个用易语言写的利用软键盘方法 当按下一个按键启动其他热键的方法 以下为源码写法 .版本 2 .支持库 she…

电气设备施工现场风险状态判断ai模型训练数据集

电气设备施工现场风险状态判断ai模型训练数据集 id:18 电气设备施工现场工人人工智能学习数据和工作环境安全数据&#xff0c;建立系统化管理体系&#xff0c;改变全球EHS范式&#xff0c;预防工业事故。数据集记录了387709例子电力设施建设以及施工现场相关的灾害安全环境数据…

发现的一种很简单的set/get封装办法

参考&#xff1a; C 中简化set/get 函数封装的 方式_c get set-CSDN博客 定义一个模板类 你可以创建一个模板类Property&#xff0c;用于封装设置和获取功能&#xff1a; template<typename T> class Property { private:T value;public:void set(const T& v) {va…

代码随想录算法训练营43期 | Day 21 —— 108.将有序数组转换为二叉搜索树、 538.把二叉搜索树转换为累加树

代码随想录算法训练营 代码随想录算法训练营43期 | Day108.将有序数组转换为二叉搜索树538.把二叉搜索树转换为累加树 代码随想录算法训练营43期 | Day 108.将有序数组转换为二叉搜索树 class Solution { private:TreeNode* traversal(vector<int>& nums, int left…

Java项目实战II基于Java+Spring Boot+MySQL的房屋租赁管理系统的设计与实现

目录 一、前言 二、技术介绍 三、系统实现 四、论文参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着城市租…

OpenAIAPI报错和ATL延迟优化

Open AI API报错&#xff1a; ————————————————加更———————————————————— 1.API Error: {“error”:{“message”:“无效的令牌”,“type”:“one_api_error”}}/报错403 调用接口不对&#xff0c;openkey的调用需要对应使用https://open…

C#和数据库高级:抽象类和抽象方法

文章目录 一、为什么使用抽象类和抽象方法&#xff1f;1.1、父类与子类的相互转换 二、抽象类和抽象方法2.1、抽象类的定义和方法声明规范2.2、使用继承多态的机制解决问题 三、抽象类的概念和使用特点总结 一、为什么使用抽象类和抽象方法&#xff1f; 1.1、父类与子类的相互…

二十种编程语言庆祝中秋节

二十种编程语言庆祝中秋节 文章目录 二十种编程语言庆祝中秋节中秋快乐&#xff01;家人们 &#x1f973;一 Python二 C三 C四 Java五 C#六 Perl七 Go八 Asp九 PHP十 JavaScript十一 JavaScript HTML十二 Visual Basic十三 早期 VB十四 Visual C十五 Delphi十六 Shell十七 Cobo…

在设计开发中,如何提高网站的用户体验?

在网站设计开发中&#xff0c;提高用户体验是至关重要的。良好的用户体验不仅能提升用户的满意度和忠诚度&#xff0c;还能增加转化率和用户留存率。以下是一些有效的方法和策略&#xff1a; 优化页面加载速度 减少HTTP请求&#xff1a;合并CSS和JavaScript文件以减少HTTP请求…

人工智能——猴子摘香蕉问题

一、实验目的 求解猴子摘香蕉问题&#xff0c;根据猴子不同的位置&#xff0c;求解猴子的移动范围&#xff0c;求解对应的过程&#xff0c;针对不同的目标状态进行求解。 二、实验内容 根据场景有猴子、箱子、香蕉&#xff0c;香蕉挂天花板上。定义多种谓词描述位置、状态等…

深度学习中常见的损失函数

在机器学习和深度学习中&#xff0c;损失函数用于衡量模型预测值与真实值之间的差异。根据任务的类型&#xff08;如回归、分类等&#xff09;&#xff0c;可以使用不同的损失函数。下面列举了一些常见的损失函数&#xff1a; 1. 回归问题中的损失函数 回归任务的目标是预测连…

信息安全数学基础(9)素数的算数基本定理

前言 在信息安全数学基础中&#xff0c;素数的算数基本定理&#xff08;也称为唯一分解定理或算术基本定理&#xff09;是一个极其重要的定理&#xff0c;它描述了正整数如何唯一地分解为素数的乘积。这个定理不仅是数论的基础&#xff0c;也是许多密码学算法&#xff08;如RSA…

微信小程序开发第五课

一 vant-app # https://vant-contrib.gitee.io/vant-weapp/#/home1.1 集成步骤 # 0 必须使用专门为小程序提供的npm包&#xff0c;通常好多包用不了&#xff0c;比如第三方包用了dom&#xff0c;小程序没有 https://developers.weixin.qq.com/miniprogram/dev/devtools/npm.h…

超详细PS2019安装教程与安装步骤图文解析!保姆级教程!(附赠PS下载地址)

步骤1&#xff1a;下载Adobe Photoshop PS CC 2023下载链接&#xff1a;https://pan.quark.cn/s/f997e116f327 下载完成后&#xff0c;解压文件到当前文件夹&#xff08;随便用什么解压软件都行&#xff0c;现在解压软件都是免费的&#xff0c;没有的到360官网下载360压缩&am…

Verilog学习之旅~

记录Verilog的学习日常~ 第一阶段&#xff1a;牛客网刷题 1.Verilog快速入门 基础语法 VL1:四选一多路器&#xff1a;case语句、条件表达符&#xff1b; VL2:异步复位的串联T触发器:T触发器的基本功能及代码实现、异步复位的概念&#xff1b; VL3:奇偶校验&#xff1a;缩…

Django 聚合查询

文章目录 一、聚合查询二、使用步骤1.准备工作2.具体使用3.分组查询&#xff08;annotate&#xff09;1.定义2.使用3.具体案例 4.F() 查询1.定义2.使用 5.Q() 查询1.定义2.查询 一、聚合查询 使用聚合查询前要先从 django.db.models 引入 Avg、Max、Min、Count、Sum&#xff0…

QT开发:C++ Qt 信号与槽机制概括性总结

引言 在上一篇文章中&#xff0c;我们详细介绍了 Qt 中信号与槽的概念以及它们的使用方法&#xff0c;相信大家已经对 Qt 信号和槽机制有了一定的理解。当然我们要想学好开发技术&#xff0c;就得打好基础&#xff0c;从现在开始掌握每一个知识点。本文将基于前一篇内容&#x…

大语言模型-教育方向数据集

大语言模型-教育方向数据集 编号论文数据集1Bitew S K, Hadifar A, Sterckx L, et al. Learning to Reuse Distractors to Support Multiple-Choice Question Generation in Education[J]. IEEE Transactions on Learning Technologies, 2022, 17: 375-390.Televic, NL, https…