WebSocket的原理及QT示例

news2025/5/13 18:29:24

一.WebSocket 介绍

1.概述

WebSocket 是一种在单个 TCP 连接上进行全双工通讯的协议,它在 2011 年被 IETF 定为标准 RFC 6455,并由 RFC7936 补充规范。与传统的 HTTP 协议不同,WebSocket 允许服务器和客户端之间进行实时、双向的数据传输,打破了 HTTP 协议请求 - 响应的模式限制,大大提高了数据传输的效率和实时性。

2.特点

全双工通信:服务器和客户端可以在任意时刻向对方发送数据,无需等待对方的请求。

实时性强:由于采用了全双工通信,数据可以即时传输,非常适合实时性要求较高的应用场景,如在线聊天、实时数据监控等。

较少的开销:WebSocket 握手阶段使用 HTTP 协议,建立连接后,数据传输不再需要像 HTTP 那样携带大量的头部信息,减少了数据传输的开销。

跨域支持:WebSocket 支持跨域通信,方便不同域名之间的服务器和客户端进行数据交互。

客户端与服务器交互图

3.应用场景

实时聊天应用:如在线客服、社交聊天等,用户可以即时收到对方发送的消息。

实时数据监控:如股票行情、传感器数据监控等,服务器可以实时将最新的数据推送给客户端。

多人在线游戏:实现游戏中玩家之间的实时交互,如位置更新、动作同步等。

二.代码示例

1.客户端代码

#include "Clientdialog.h"

#include <QLabel>

#include <QWidget>

#include <QHBoxLayout>

#include <QVBoxLayout>

#include <QtCore>

#include <QDebug>

#include <iostream>

ClientDialog::ClientDialog(QWidget *parent)

    : QWidget(parent)

{

    //layout1

    QLabel *iplabel = new QLabel("Server IP");

    m_iplineedit =new QLineEdit;

    m_iplineedit->setText("127.0.0.1");

    QLabel *portlabel =new QLabel("Server端口");

    m_portspinbox = new QSpinBox;

    m_portspinbox->setRange(0,65535);

    m_portspinbox->setValue(5123);

    m_linkbutton = new QPushButton("连接");

    m_disconnectbutton = new QPushButton("断开");

    pButtonGroup = new QButtonGroup();

    pButtonGroup->setExclusive(true);

    m_linkbutton->setCheckable(true);

    m_disconnectbutton->setCheckable(true);

    pButtonGroup->addButton(m_linkbutton,0);

    pButtonGroup->addButton(m_disconnectbutton,1);

    QHBoxLayout *qhboxlayout1 = new QHBoxLayout;

    qhboxlayout1->addWidget(iplabel);

    qhboxlayout1->addWidget(m_iplineedit);

    qhboxlayout1->addWidget(portlabel);

    qhboxlayout1->addWidget(m_portspinbox);

    qhboxlayout1->addWidget(m_linkbutton);

    qhboxlayout1->addWidget(m_disconnectbutton);

    //layout2

    QLabel *sendmessagelabel = new QLabel("发送消息");

    QHBoxLayout *qhboxlayout2 = new QHBoxLayout;

    qhboxlayout2->addWidget(sendmessagelabel);

    //layout3

    m_sendmessagetextedit = new QTextEdit;

    m_sendmessagetextedit->setFixedHeight(50);

    m_sendbutton = new QPushButton("发送");

    m_sendbutton->setFixedHeight(50);

    QHBoxLayout *qhboxlayout3 = new QHBoxLayout;

    qhboxlayout3->addWidget(m_sendmessagetextedit);

    qhboxlayout3->addWidget(m_sendbutton);

    //layout4

    QLabel *receivemessagelabel = new QLabel("接收消息");

    QHBoxLayout *qhboxlayout4 = new QHBoxLayout;

    qhboxlayout4->addWidget(receivemessagelabel);

    //layout5

    m_receivemessageTextEdit = new QTextEdit;

    QHBoxLayout *qhboxlayout5 = new QHBoxLayout;

    qhboxlayout5->addWidget(m_receivemessageTextEdit);

    m_receivemessageTextEdit->setReadOnly(true);

    //layout6

    statusLabel = new QLabel("连接状态");

    m_clean = new QPushButton("清除");

    QHBoxLayout *qhboxlayout6 = new QHBoxLayout;

    qhboxlayout6->addWidget(statusLabel);

    qhboxlayout6->addStretch();

    qhboxlayout6->addWidget(m_clean);

    //

    QVBoxLayout *mainlayout = new QVBoxLayout;

    mainlayout->addLayout(qhboxlayout1,1);

    mainlayout->addLayout(qhboxlayout2,0.5);

    mainlayout->addLayout(qhboxlayout3,1);

    mainlayout->addLayout(qhboxlayout4,0.5);

    mainlayout->addLayout(qhboxlayout5,3);

    mainlayout->addLayout(qhboxlayout6,1);

    setLayout(mainlayout);

    setWindowTitle("Websocket Client");

    this->setFixedSize(800, 600); // 窗口固定为800x600像素,无法缩放

    connect(m_linkbutton,SIGNAL(clicked(bool)),this,SLOT(connectToServer()));

    connect(m_disconnectbutton,SIGNAL(clicked(bool)),this,SLOT(stopClicked()));

    connect(m_sendbutton,SIGNAL(clicked(bool)),this,SLOT(onSendButtonClicked()));

    connect(m_clean,SIGNAL(clicked(bool)),this,SLOT(onCleanButtonClicked()));

    connect(&m_websocket,SIGNAL(connected()),this,SLOT(onconnected()));

    connect(&m_websocket,SIGNAL(disconnected()),this,SLOT(closeConnection()));

    connect(&m_websocket,SIGNAL(textMessageReceived(QString)),this,SLOT(onTextMessageReceived(QString)));

}

ClientDialog::~ClientDialog()

{

    m_websocket.errorString();

    m_websocket.close();

}

//断开连接操作

void ClientDialog::closeConnection(){

    m_linkbutton->setEnabled(true);

    m_disconnectbutton->setEnabled(false);

    m_sendmessagetextedit->setEnabled(false);

    m_sendbutton->setEnabled(false);

    m_receivemessageTextEdit->setEnabled(false);

    m_clean->setEnabled(false);

    statusLabel->setText(tr("disconnected"));

}

//连接服务器

void ClientDialog::connectToServer()

{

    QString path = QString("ws://%1:%2").arg(m_iplineedit->text()).arg(m_portspinbox->text());

    QUrl url = QUrl(path);

    m_websocket.open(url);

}

//连接上之后

void ClientDialog::onconnected(){

    qDebug() << "hello word!";

    statusLabel->setText(tr("connected"));

    m_linkbutton->setEnabled(false);

    m_disconnectbutton->setEnabled(true);

    m_sendmessagetextedit->setEnabled(true);

    m_sendbutton->setEnabled(true);

    m_receivemessageTextEdit->setEnabled(true);

    m_clean->setEnabled(true);

}

//收到消息

void ClientDialog::onTextMessageReceived(const QString &message)

{

    QString time = current_date_time->currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz ddd");

    m_receivemessageTextEdit->setText(time + "\r\n" + "message: " + message);

}

//断开

void ClientDialog::stopClicked()

{

    m_websocket.close();

}

//发送消息

void ClientDialog::onSendButtonClicked()

{

    QString msg= m_sendmessagetextedit->document()->toPlainText();

    m_websocket.sendTextMessage(msg);

}

//清除内容

void ClientDialog::onCleanButtonClicked()

{

    m_receivemessageTextEdit->clear();

}

2.服务端代码

#include "webserver.h"

#include "ui_webserver.h"

#include <QtCore/QVariant>

#include <QtWidgets/QApplication>

#include <QtWidgets/QButtonGroup>

#include <QtWidgets/QHeaderView>

#include <QtWidgets/QLabel>

#include <QtWidgets/QListWidget>

#include <QtWidgets/QPushButton>

#include <QtWidgets/QSpinBox>

#include <QtWidgets/QTextBrowser>

#include <QtWidgets/QWidget>

#include <QHBoxLayout>

webserver::webserver(QWidget *parent) :

    QWidget(parent),

    ui(new Ui::webserver)

{

    ui->setupUi(this);

    {

         //qhboxLayout1部分代码

         QLabel* monitorLabel= new QLabel("监听端口");

         m_monitorSpinBox = new QSpinBox();

         m_monitorSpinBox->setRange(0,65535);

         m_monitorSpinBox->setValue(5123);

         m_startButton = new QPushButton("启动服务");

         m_stopButton = new QPushButton("停止服务");

         m_stopButton->setEnabled(false);

         QHBoxLayout *qhboxLayout = new QHBoxLayout;

         qhboxLayout->addWidget(monitorLabel);

         qhboxLayout->addWidget(m_monitorSpinBox);

         qhboxLayout->addWidget(m_startButton);

         qhboxLayout->addWidget(m_stopButton);

        //qhboxLayout2部分代码

          QLabel* sendLabel=new QLabel("发送消息");

          sendLabel->setFixedHeight(30);

          QHBoxLayout *qhboxLayout2 = new QHBoxLayout;

          qhboxLayout2->addWidget(sendLabel);

        //qhboxLayout3部分代码

          m_sendTextedit = new QTextEdit;

          m_sendTextedit = new QTextEdit();

          m_sendTextedit->setEnabled(false);

          m_sendTextedit->setFixedHeight(80);

          m_sendButton= new QPushButton("发送");

          m_sendButton->setEnabled(false);

          m_sendButton->setFixedHeight(50);

          QHBoxLayout *qhboxlayout3 = new QHBoxLayout;

          qhboxlayout3->addWidget(m_sendTextedit,2);

          qhboxlayout3->addWidget(m_sendButton,1);

        //qvboxlayout411

          QLabel* receiveLabel = new QLabel("接收消息");

          receiveLabel->setFixedHeight(30);

          m_receiveTextEdit = new QTextEdit();

          m_receiveTextEdit->setReadOnly(true);

          QVBoxLayout *qvboxlayout411 = new QVBoxLayout;

          qvboxlayout411->addWidget(receiveLabel);

          qvboxlayout411->addWidget(m_receiveTextEdit);

            //qhboxlayout412

          m_cleanButton = new QPushButton("清除");

          m_cleanButton->setEnabled(false);

          QHBoxLayout *qhboxlayout412 = new QHBoxLayout;

          qhboxlayout412->addStretch();

          qhboxlayout412->addWidget(m_cleanButton);

        //qvboxlayout41

          QVBoxLayout *qvboxlayout41 = new QVBoxLayout;

          qvboxlayout41->addLayout(qvboxlayout411);

          qvboxlayout41->addLayout(qhboxlayout412);

        //qvboxlayout42

          QLabel* linkclientLabel=new QLabel("连接客户端");

          linkclientLabel->setFixedHeight(30);

          m_linkclientListWidget=new QListWidget;

          QVBoxLayout* qvboxlayout42 = new QVBoxLayout;

          qvboxlayout42->addWidget(linkclientLabel);

          qvboxlayout42->addWidget(m_linkclientListWidget);

        //qvboxlayout4

          QHBoxLayout *qhboxlayout4 = new QHBoxLayout;

          qhboxlayout4->addLayout(qvboxlayout41,2);

          qhboxlayout4->addLayout(qvboxlayout42,1);

         //mainlayout

          QVBoxLayout *mainLayout = new QVBoxLayout;

          mainLayout->addLayout(qhboxLayout,1);

          mainLayout->addLayout(qhboxLayout2,1);

          mainLayout->addLayout(qhboxlayout3,1);

          mainLayout->addLayout(qhboxlayout4,3);

          this->setLayout(mainLayout);

          this->setWindowTitle("Websocket Server -- Neo");

          this->setFixedSize(800, 600); // 窗口固定为800x600像素,无法缩放

    }

    m_WebSocketServer=new QWebSocketServer("server",QWebSocketServer::NonSecureMode);

    connect(m_WebSocketServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));

    connect(m_WebSocketServer, SIGNAL(closed()), this, SLOT(onClosed()));

    connect(m_WebSocketServer, SIGNAL(serverError(QWebSocketProtocol::CloseCode)),

            this, SLOT(onServerError(QWebSocketProtocol::CloseCode)));

    connect(m_startButton,SIGNAL(clicked(bool)),this,SLOT(onStartButtonClick()));

    connect(m_stopButton,SIGNAL(clicked(bool)),this,SLOT(onStopButtonClick()));

    connect(m_cleanButton,SIGNAL(clicked(bool)),this,SLOT(onCleanButtonClick()));

    connect(m_sendButton,SIGNAL(clicked(bool)),this,SLOT(onSendButtonClick()));

}

webserver::~webserver()

{

    if(m_WebSocketServer)

    {

        m_WebSocketServer->close();

    }

    delete ui;

}

//开启服务

void webserver::onStartButtonClick(){

    int i_port = m_monitorSpinBox->text().toInt();

    m_WebSocketServer->listen(QHostAddress::Any,i_port);

    m_startButton->setEnabled(false);

    m_stopButton->setEnabled(true);

    qDebug()<<m_WebSocketServer->isListening();

    qDebug()<<m_WebSocketServer->serverPort();

    qDebug()<<m_WebSocketServer->serverAddress();

}

//停止服务

void webserver::onStopButtonClick(){

    m_startButton->setEnabled(true);

    m_stopButton->setEnabled(false);

    m_WebSocketServer->close();

}

//发送信息

void webserver::onSendButtonClick(){

    QString msg = m_sendTextedit->document()->toPlainText();

    int currenRow = m_linkclientListWidget->currentRow();//当前单击选中ListWidget控件的行号

    if(currenRow==-1)

    {

        currenRow = 0;

    }

    QString key = m_linkclientListWidget->item(currenRow)->text();

    if(_hashIpPort2PWebSocket.contains(key))

    {

        _hashIpPort2PWebSocket.value(key)->sendTextMessage(msg);

    }

}

void webserver::onCleanButtonClick(){

    m_receiveTextEdit->clear();

}

//连接上之后

void webserver::onNewConnection(){

    qDebug() << "connect ok";

    m_startButton->setEnabled(false);

    m_stopButton->setEnabled(true);

    m_sendTextedit->setEnabled(true);

    m_sendButton->setEnabled(true);

    m_cleanButton->setEnabled(true);

    QWebSocket *pWebSocket = m_WebSocketServer->nextPendingConnection();

    connect(pWebSocket,SIGNAL(textMessageReceived(QString)),this,SLOT(slot_processTextMessage(QString)));

    connect(pWebSocket,SIGNAL(disconnected()),this,SLOT(slot_socketDisconnected()));

    connect(pWebSocket, SIGNAL(error(QAbstractSocket::SocketError)),

            this      , SLOT(slot_error(QAbstractSocket::SocketError)));

    quint32 ipv4Address =  pWebSocket->peerAddress().toIPv4Address();

    QString ipString = QHostAddress(ipv4Address).toString();

    _hashIpPort2PWebSocket.insert(QString("%1-%2").arg(ipString).arg(pWebSocket->peerPort()),pWebSocket);

    QString item = QString("%1-%2").arg(ipString).arg(pWebSocket->peerPort());

    m_linkclientListWidget->addItem(item);

}

//停止之后

void webserver::onClosed()

{

    QList<QWebSocket *> _listWebSocket = _hashIpPort2PWebSocket.values();

    for(int index = 0; index < _listWebSocket.size(); index++)

    {

        _listWebSocket.at(index)->close();

    }

    _hashIpPort2PWebSocket.clear();

    m_linkclientListWidget->clear();

}

//连接错误

void webserver::onServerError(QWebSocketProtocol::CloseCode closeCode)

{

    QWebSocket *pWebSocket = dynamic_cast<QWebSocket *>(sender());

    if(!pWebSocket)

    {

        return;

    }

}

void webserver::slot_error(QAbstractSocket::SocketError error)

{

    QWebSocket *pWebSocket = dynamic_cast<QWebSocket *>(sender());

    if(!pWebSocket)

    {

        return;

    }

}

//收到消息并显示

void webserver::slot_processTextMessage(QString message){

    QWebSocket *pWebSocket = dynamic_cast<QWebSocket *>(sender());

    if(!pWebSocket)

    {

        return;

    }

    QString time = current_date_time->currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz ddd");

    quint32 ipv4Address =  pWebSocket->peerAddress().toIPv4Address();

    QString ipString = QHostAddress(ipv4Address).toString();

    QString item = QString("IP: %1, port: %2").arg(ipString).arg(pWebSocket->peerPort());

    m_receiveTextEdit->append(time+ "\r\n" + item + "\r\n" + "message: " + message + "\r\n");

    //qDebug()<< pWebSocket->peerAddress().toString();

    //qDebug() << "Client IP address: " << ipString;

}

//连接断开的操作

void webserver::slot_socketDisconnected(){

    QWebSocket *pWebSocket = dynamic_cast<QWebSocket *>(sender());

    if(!pWebSocket)

    {

        return;

    }

    //qDebug() << __FILE__ << __LINE__ << __FUNCTION__;

    quint32 ipv4Address =  pWebSocket->peerAddress().toIPv4Address();

    QString ipString = QHostAddress(ipv4Address).toString();

    QString item1 = QString("%1-%2").arg(ipString).arg(pWebSocket->peerPort());

    _hashIpPort2PWebSocket.remove(QString("%1-%2").arg(ipString).arg(pWebSocket->peerPort()));

    QListWidgetItem *item3;

    for(int i=0;i<m_linkclientListWidget->count();i++)

    {

        QString str = m_linkclientListWidget->item(i)->text();

        if(str == item1)

        {

            item3 = m_linkclientListWidget->takeItem(i);

            m_linkclientListWidget->removeItemWidget(item3);

            delete item3;

        }

    }

}

void webserver::on_m_linkclientListWidget_clicked(const QModelIndex &index)

{

int currenRow = m_linkclientListWidget->currentRow();

}

3.完整工程代码下载

https://download.csdn.net/download/xieliru/90787178

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2374851.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3:十二、图形看板- echart图表-柱状图、饼图

一、效果 如图展示增加了饼图和柱状图,并且优化了浏览器窗口大小更改,图表随着改变 二、 饼图 1、新建组件文件 新增组件EchartsExaminePie.vue,用于存储审核饼图的图表 2、写入组件信息 (1)视图层 写入一个div,写入变量chart和图表宽高 <template><div ref…

2025年best好用的3dsmax插件和脚本

copitor 可以从一个3dsmax场景里将物体直接复制到另一个场景中 Move to surface 这个插件可以将一些物体放到一个平面上 instancer 实体器&#xff0c;举例&#xff1a;场景中有若干独立的光源&#xff0c;不是实体对象&#xff0c;我们可以使用instancer将他变成实体。 paste …

HAProxy + Keepalived + Nginx 高可用负载均衡系统

1. 项目背景 在现代Web应用中&#xff0c;高可用性和负载均衡是两个至关重要的需求。本项目旨在通过HAProxy实现流量分发&#xff0c;通过Keepalived实现高可用性&#xff0c;通过Nginx提供后端服务。该架构能够确保在单点故障的情况下&#xff0c;系统仍然能够正常运行&#…

5.12 note

Leetcode 图 邻接矩阵的dfs遍历 class Solution { private: vector<vector<int>> paths; vector<int> path; void dfs(vector<vector<int>>& graph, int node) { // 到n - 1结点了保存 if (node graph.size() - 1)…

跨时钟域(CDC,clock domain crossing)信号处理

参考视频&#xff1a; 数字IC&#xff0c;FPGA秋招【单bit信号的CDC跨时钟域处理手撕代码合集】_哔哩哔哩_bilibili 一、亚稳态 原因是&#xff1a;建立时间和保持时间没有保持住。然后在下图的红框里面&#xff0c;产生亚稳态。因为电路反馈机制&#xff0c;最后大概率会恢复…

OBS studio 减少音频中的杂音(噪音)

1. 在混音器中关闭除 麦克风 之外的所有的音频输入设备 2.在滤镜中增加“噪声抑制”和“噪声门限”

智能手表 MCU 任务调度图

智能手表 MCU 任务调度图 处理器平台&#xff1a;ARM Cortex-M33 系统架构&#xff1a;事件驱动 多任务 RTOS RTOS&#xff1a;FreeRTOS&#xff08;或同类实时内核&#xff09; 一、任务调度概览 任务名称优先级周期性功能描述App_MainTask中否主循环调度器&#xff0c;系统…

S7-1500——零基础入门2、PLC的硬件架构

PLC的硬件架构 一,西门子PLC概述二,CPU介绍三,数字量模块介绍四,模拟量模块介绍五,其他模块介绍一,西门子PLC概述 本节主要内容 西门子PLC硬件架构,主要内容包括PLC概述、组成、功能及S7-1500 demo的组成与安装演示。 介绍了PLC的定义、功能、应用场合,以及与继电器控…

【PmHub后端篇】Skywalking:性能监控与分布式追踪的利器

在微服务架构日益普及的当下&#xff0c;对系统的性能监控和分布式追踪显得尤为重要。本文将详细介绍在 PmHub 项目中&#xff0c;如何使用 Skywalking 实现对系统的性能监控和分布式追踪&#xff0c;以及在这过程中的一些关键技术点和实践经验。 1 分布式链路追踪概述 在微服…

利用“Flower”实现联邦机器学习的实战指南

一个很尴尬的现状就是我们用于训练 AI 模型的数据快要用完了。所以我们在大量的使用合成数据&#xff01; 据估计&#xff0c;目前公开可用的高质量训练标记大约有 40 万亿到 90 万亿个&#xff0c;其中流行的 FineWeb 数据集包含 15 万亿个标记&#xff0c;仅限于英语。 作为…

【RabbitMQ】应用问题、仲裁队列(Raft算法)和HAProxy负载均衡

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【中间件】企业级中间件剖析 一、幂等性保障 什么是幂等性&#xff1f; 幂等性是指对一个系统进行重复调用&#xff08;相同参数&#xff09;&#xff0c;无论同一操作执行多少次&#xff0c;这些请求…

软件设计师-错题笔记-系统开发与运行

1. 解析&#xff1a; A&#xff1a;模块是结构图的基本成分之一&#xff0c;用矩形表示 B&#xff1a;调用表示模块之间的调用关系&#xff0c;通过箭头等符号在结构图中体现 C&#xff1a;数据用于表示模块之间的传递的信息&#xff0c;在结构图中会涉及数据的流向等表示 …

C#简易Modbus从站仿真器

C#使用NModbus库&#xff0c;编写从站仿真器&#xff0c;支持Modbus TCP访问&#xff0c;支持多个从站地址和动态启用/停用从站&#xff08;模拟离线&#xff09;&#xff0c;支持数据变化&#xff0c;可以很方便实现&#xff0c;最终效果如图所示。 项目采用.net framework 4.…

【深度学习】目标检测算法大全

目录 一、R-CNN 1、R-CNN概述 2、R-CNN 模型总体流程 3、核心模块详解 &#xff08;1&#xff09;候选框生成&#xff08;Selective Search&#xff09; &#xff08;2&#xff09;深度特征提取与微调 2.1 特征提取 2.2 网络微调&#xff08;Fine-tuning&#xff09; …

视觉-语言-动作模型:概念、进展、应用与挑战(下)

25年5月来自 Cornell 大学、香港科大和希腊 U Peloponnese 的论文“Vision-Language-Action Models: Concepts, Progress, Applications and Challenges”。 视觉-语言-动作 (VLA) 模型标志着人工智能的变革性进步&#xff0c;旨在将感知、自然语言理解和具体动作统一在一个计…

一键解锁嵌入式UI开发——LVGL的“万能配方”

面对碎片化的嵌入式硬件生态&#xff0c;LVGL堪称开发者手中的万能配方。它通过统一API接口屏蔽底层差异&#xff0c;配合丰富的预置控件&#xff08;如按钮、图表、滑动条&#xff09;与动态渲染引擎&#xff0c;让工程师无需深入图形学原理&#xff0c;效率提升肉眼可见。 L…

智慧城市综合运营管理系统Axure原型

这款Axure原型的设计理念紧紧围绕城市管理者的需求展开。它旨在打破传统城市管理中信息孤岛的局面&#xff0c;通过统一标准接入各类业务系统&#xff0c;实现城市运营管理信息资源的全面整合与共享。以城市管理者为中心&#xff0c;为其提供一个直观、便捷、高效的协同服务平台…

Qwen智能体qwen_agent与Assistant功能初探

Qwen智能体qwen_agent与Assistant功能初探 一、Qwen智能体框架概述 Qwen&#xff08;通义千问&#xff09;智能体框架是阿里云推出的新一代AI智能体开发平台&#xff0c;其核心模块qwen_agent.agent提供了一套完整的智能体构建解决方案。该框架通过模块化设计&#xff0c;将L…

可视化图解算法37:序列化二叉树-II

1. 题目 描述 请实现两个函数&#xff0c;分别用来序列化和反序列化二叉树&#xff0c;不对序列化之后的字符串进行约束&#xff0c;但要求能够根据序列化之后的字符串重新构造出一棵与原二叉树相同的树。 二叉树的序列化(Serialize)是指&#xff1a;把一棵二叉树按照某种遍…

C++GO语言微服务和服务发现②

01 创建go-micro项目-查看生成的 proto文件 02 创建go-micro项目-查看生成的main文件和handler ## 创建 micro 服务 命令&#xff1a;micro new --type srv test66 框架默认自带服务发现&#xff1a;mdns。 使用consul服务发现&#xff1a; 1. 初始consul服务发现&…