QT应用编程: 编写MQTT客户端登录OnetNet服务器完成主题订阅与发布

简介: QT应用编程: 编写MQTT客户端登录OnetNet服务器完成主题订阅与发布

一、环境介绍

QT版本: 5.12.6


编译器:  MinGW 32


MQTT协议: 参照3.1.1版本文档自己编写 (不是使用QT的qmqtt)


功能介绍:  使用QT编写MQTT客户端(根据mqtt官方文档3.1.1,自己实现过程代码,没有使用其他库),登录OneNet物联网服务器,完成主题订阅、发布等操作。


项目完整源码下载地址: https://download.csdn.net/download/xiaolong1126626497/18725462


软件运行效果图: (2021/06/01 21:30 更新,修复已知BUG)  新加入:  心跳包、域名检测功能

image.png

image.png

image.png

二、在OneNet上创建产品

地址:https://open.iot.10086.cn/

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

手机APP下载地址:https://download.csdn.net/download/xiaolong1126626497/18697132

image.pngimage.png

三、OneNet的MQTT介绍

onenet服务器的地址:  https://open.iot.10086.cn/doc/mqtt/book/device-develop/manual.html

image.png

设备接入说明: https://open.iot.10086.cn/doc/mqtt/book/get-start/connect.html

image.png

主题订阅与发布的格式说明: https://open.iot.10086.cn/doc/mqtt/book/device-develop/protocol.html

image.png

订阅主题的格式:

$sys/{pid}/{device-name}/dp/post/json/accepted  订阅设备数据点上报成功的消息
$sys/{pid}/{device-name}/dp/post/json/rejected  订阅设备数据点上报失败的消息
$sys/{pid}/{device-name}/dp/post/json/+ 订阅设备数据点上报结果
$sys/{pid}/{device-name}/cmd/request/+  订阅设备所有命令消息
$sys/{pid}/{device-name}/cmd/response/+/+ 订阅设备所有命令应答结果消息
$sys/{pid}/{device-name}/cmd/#  订阅设备所有命令相关消息
$sys/{pid}/{device-name}/#  订阅设备所有相关消息
说明:  参数里的pid就是产品的ID(注意是产品ID不是设备ID),device-name 就是产品的名称。
如果要订阅设备所有相关信息,就可以这样写:
$sys/427519/GreeningManagement/#

主题发布(数据上传): https://open.iot.10086.cn/doc/mqtt/book/device-develop/topics/dp-topics.html

image.png

设备可以通过向系统固定 topic:$sys/{pid}/{device-name}/dp/post/json 发送数据点存储消息,消息中payload字段数据内容仅支持json格式.
发布主题的格式: $sys/427519/GreeningManagement/dp/post/json
如果同时上传温度、湿度、光照度的消息就可以这样写:
{"id":666,"dp":{"temperature":[{"v":21}],"humidity":[{"v":40}],"Light":[{"v":100}]}}
在代码里写上面这串数据时,里面的"要记得转义。
就应该这样写:
{\"id\":666,\"dp\":{\"temperature\":[{\"v\":21}],\"humidity\":[{\"v\":40}],\"Light\":[{\"v\":100}]}}

安全鉴权(就是生成MQTT登录的密码、非常重要): https://open.iot.10086.cn/doc/mqtt/book/manual/auth/token.html

image.png

下载密码生成工具: https://open.iot.10086.cn/doc/mqtt/book/manual/auth/tool.html

image.png

生成登录面示例:

image.png

参数说明:


res选项参数的格式: products/{产品ID}/devices/{设备名称}

et是设置token过期时间:算出1970-1-1到你想要设置的到期时间,单位是秒,填入即可。

key的参数格式: 就是设备创建之后,在设备详情页的key声明。


根据上面工具获取、得到的MQTT协议登录密码就是下面这个:

version=2018-10-31&res=products%2F427519%2Fdevices%2FGreeningManagement&et=1631378104&method=md5&sign=xz3tM8A31jIrkQ3S1mOcqQ%3D%3D

计算到期时间的代码:(Linux)

#include <stdio.h>
#include <time.h>
#include <time.h>
int main()
{
    time_t time_sec;
    time_sec=time(NULL);  //当前的秒单位时间--UTC时间
  printf("当前时间(秒):%ld\n",time_sec);
  printf("加120天的时间(秒):%ld\n",time_sec+120*24*60*60);
  return 0;
}
wbyq@wbyq:~$ ./a.out 
当前时间(秒):1621010104
加120天的时间(秒):1631378104

四、QT实现mqtt协议核心代码

image.png

4.1 mqtt.cpp

#include "mqtt.h"
//连接成功服务器回应 20 02 00 00
//客户端主动断开连接 e0 00
const quint8 parket_connetAck[] = {0x20,0x02,0x00,0x00};
const quint8 parket_disconnet[] = {0xe0,0x00};
const quint8 parket_heart[] = {0xc0,0x00};
const quint8 parket_heart_reply[] = {0xc0,0x00};
const quint8 parket_subAck[] = {0x90,0x03};
MQTT_WorkClass::~MQTT_WorkClass()
{
    qDebug()<<"析构函数---TCP";
}
void MQTT_WorkClass::run()
{
    qDebug()<<"执行:run";
    if(timer)
    {
        delete  timer;
        timer=nullptr;
    }
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(EndEvenLoop()));
    socket_type=0;
    //连接到服务器
    ConnectMqttServer(m_ip,m_port);
    //开始事件循环
    StartEvenLoop();
    //初始化mqtt协议
    MQTT_Init();
    //连接mqtt协议
    if(MQTT_Connect(m_MQTT_ClientID.toUtf8().data(),m_MQTT_UserName.toUtf8().data(),m_MQTT_PassWord.toUtf8().data()))
    {
        LogSend("MQTT服务器登录失败.\n");
    }
    else
    {
        LogSend("MQTT服务器登录成功.\n");
    }
}
void MQTT_WorkClass::MQTT_Init(void)
{
    //缓冲区赋值
  mqtt_rxbuf = _mqtt_rxbuf;
    mqtt_rxlen = sizeof(_mqtt_rxbuf);
  mqtt_txbuf = _mqtt_txbuf;
    mqtt_txlen = sizeof(_mqtt_txbuf);
  memset(mqtt_rxbuf,0,mqtt_rxlen);
  memset(mqtt_txbuf,0,mqtt_txlen);
}
/*
函数功能: 登录服务器
函数返回值: 0表示成功 1表示失败
*/
quint8 MQTT_WorkClass::MQTT_Connect(char *ClientID,char *Username,char *Password)
{
    quint8 i,j;
    int ClientIDLen = strlen(ClientID);
    int UsernameLen = strlen(Username);
    int PasswordLen = strlen(Password);
    int DataLen;
  mqtt_txlen=0;
  //可变报头+Payload  每个字段包含两个字节的长度标识
    DataLen = 10 + (ClientIDLen+2) + (UsernameLen+2) + (PasswordLen+2);
  //固定报头
  //控制报文类型
    mqtt_txbuf[mqtt_txlen++] = 0x10;    //MQTT Message Type CONNECT
  //剩余长度(不包括固定头部)
  do
  {
        quint8 encodedByte = DataLen % 128;
    DataLen = DataLen / 128;
    // if there are more data to encode, set the top bit of this byte
    if ( DataLen > 0 )
      encodedByte = encodedByte | 128;
    mqtt_txbuf[mqtt_txlen++] = encodedByte;
  }while ( DataLen > 0 );
  //可变报头
  //协议名
    mqtt_txbuf[mqtt_txlen++] = 0;         // Protocol Name Length MSB    
    mqtt_txbuf[mqtt_txlen++] = 4;           // Protocol Name Length LSB    
    mqtt_txbuf[mqtt_txlen++] = 'M';         // ASCII Code for M    
    mqtt_txbuf[mqtt_txlen++] = 'Q';         // ASCII Code for Q    
    mqtt_txbuf[mqtt_txlen++] = 'T';         // ASCII Code for T    
    mqtt_txbuf[mqtt_txlen++] = 'T';         // ASCII Code for T    
  //协议级别
    mqtt_txbuf[mqtt_txlen++] = 4;           // MQTT Protocol version = 4   对于 3.1.1 版协议,协议级别字段的值是 4(0x04)   
  //连接标志
    mqtt_txbuf[mqtt_txlen++] = 0xc2;          // conn flags 
    mqtt_txbuf[mqtt_txlen++] = 0;           // Keep-alive Time Length MSB    
    mqtt_txbuf[mqtt_txlen++] = 100;         // Keep-alive Time Length LSB  100S心跳包    保活时间
    mqtt_txbuf[mqtt_txlen++] = BYTE1(ClientIDLen);// Client ID length MSB    
    mqtt_txbuf[mqtt_txlen++] = BYTE0(ClientIDLen);// Client ID length LSB   
  memcpy(&mqtt_txbuf[mqtt_txlen],ClientID,ClientIDLen);
    mqtt_txlen += ClientIDLen;
    if(UsernameLen > 0)
    {   
        mqtt_txbuf[mqtt_txlen++] = BYTE1(UsernameLen);    //username length MSB    
        mqtt_txbuf[mqtt_txlen++] = BYTE0(UsernameLen);      //username length LSB    
    memcpy(&mqtt_txbuf[mqtt_txlen],Username,UsernameLen);
        mqtt_txlen += UsernameLen;
    }
    if(PasswordLen > 0)
    {    
        mqtt_txbuf[mqtt_txlen++] = BYTE1(PasswordLen);    //password length MSB    
        mqtt_txbuf[mqtt_txlen++] = BYTE0(PasswordLen);      //password length LSB  
    memcpy(&mqtt_txbuf[mqtt_txlen],Password,PasswordLen);
        mqtt_txlen += PasswordLen; 
    }    
    //清空数据
    memset(mqtt_rxbuf,0,mqtt_rxlen);
    ReadData.clear();
    MQTT_SendBuf(mqtt_txbuf,mqtt_txlen);
    //开始事件循环
    StartEvenLoop();
    if(ReadData.length()==0)
    {
        //开始事件循环
        StartEvenLoop();
    }
    memcpy((char *)mqtt_rxbuf,ReadData.data(),ReadData.length());
    //CONNECT
    if(mqtt_rxbuf[0]==parket_connetAck[0] && mqtt_rxbuf[1]==parket_connetAck[1]) //连接成功
    {
        return 0;//连接成功
    }
  return 1;
}
/*
函数功能: MQTT订阅/取消订阅数据打包函数
函数参数:
    topic       主题   
    qos         消息等级 0:最多分发一次  1: 至少分发一次  2: 仅分发一次
    whether     订阅/取消订阅请求包 (1表示订阅,0表示取消订阅)
返回值: 0表示成功 1表示失败
*/
quint8 MQTT_WorkClass::MQTT_SubscribeTopic(char *topic,quint8 qos,quint8 whether)
{    
    quint8 i,j;
  mqtt_txlen=0;
    int topiclen = strlen(topic);
  int DataLen = 2 + (topiclen+2) + (whether?1:0);//可变报头的长度(2字节)加上有效载荷的长度
  //固定报头
  //控制报文类型
    if(whether)mqtt_txbuf[mqtt_txlen++] = 0x82; //消息类型和标志订阅
    else  mqtt_txbuf[mqtt_txlen++] = 0xA2;    //取消订阅
  //剩余长度
  do
  {
        quint8 encodedByte = DataLen % 128;
    DataLen = DataLen / 128;
    // if there are more data to encode, set the top bit of this byte
    if ( DataLen > 0 )
      encodedByte = encodedByte | 128;
    mqtt_txbuf[mqtt_txlen++] = encodedByte;
  }while ( DataLen > 0 ); 
  //可变报头
    mqtt_txbuf[mqtt_txlen++] = 0;     //消息标识符 MSB
    mqtt_txbuf[mqtt_txlen++] = 0x0A;        //消息标识符 LSB
  //有效载荷
    mqtt_txbuf[mqtt_txlen++] = BYTE1(topiclen);//主题长度 MSB
    mqtt_txbuf[mqtt_txlen++] = BYTE0(topiclen);//主题长度 LSB   
  memcpy(&mqtt_txbuf[mqtt_txlen],topic,topiclen);
    mqtt_txlen += topiclen;
    if(whether)
    {
       mqtt_txbuf[mqtt_txlen++] = qos;//QoS级别
    }
    ReadData.clear();
    MQTT_SendBuf(mqtt_txbuf,mqtt_txlen);
    //开始事件循环
    StartEvenLoop();
    if(ReadData.length()==0)
    {
        //开始事件循环
        StartEvenLoop();
    }
    memcpy((char *)mqtt_rxbuf,ReadData.data(),ReadData.length());
    if(mqtt_rxbuf[0]==parket_subAck[0] && mqtt_rxbuf[1]==parket_subAck[1]) //订阅成功
    {
        return 0;//订阅成功
    }
  return 1; //失败
}
//MQTT发布数据打包函数
//topic   主题 
//message 消息
//qos     消息等级 
quint8 MQTT_WorkClass::MQTT_PublishData(char *topic, char *message, quint8 qos)
{  
    int topicLength = strlen(topic);    
    int messageLength = strlen(message);     
    static quint16 id=0;
  int DataLen;
  mqtt_txlen=0;
  //有效载荷的长度这样计算:用固定报头中的剩余长度字段的值减去可变报头的长度
  //QOS为0时没有标识符
  //数据长度             主题名   报文标识符   有效载荷
    if(qos) DataLen = (2+topicLength) + 2 + messageLength;       
    else  DataLen = (2+topicLength) + messageLength;   
    //固定报头
  //控制报文类型
    mqtt_txbuf[mqtt_txlen++] = 0x30;    // MQTT Message Type PUBLISH  
  //剩余长度
  do
  {
        quint8 encodedByte = DataLen % 128;
    DataLen = DataLen / 128;
    // if there are more data to encode, set the top bit of this byte
    if ( DataLen > 0 )
      encodedByte = encodedByte | 128;
    mqtt_txbuf[mqtt_txlen++] = encodedByte;
  }while ( DataLen > 0 ); 
    mqtt_txbuf[mqtt_txlen++] = BYTE1(topicLength);//主题长度MSB
    mqtt_txbuf[mqtt_txlen++] = BYTE0(topicLength);//主题长度LSB 
  memcpy(&mqtt_txbuf[mqtt_txlen],topic,topicLength);//拷贝主题
    mqtt_txlen += topicLength;
  //报文标识符
    if(qos)
    {
        mqtt_txbuf[mqtt_txlen++] = BYTE1(id);
        mqtt_txbuf[mqtt_txlen++] = BYTE0(id);
        id++;
    }
  memcpy(&mqtt_txbuf[mqtt_txlen],message,messageLength);
    mqtt_txlen += messageLength;
    ReadData.clear();
  MQTT_SendBuf(mqtt_txbuf,mqtt_txlen);
    //开始事件循环
    StartEvenLoop();
    return mqtt_txlen;
}
void MQTT_WorkClass::MQTT_SentHeart(void)
{
    MQTT_SendBuf((quint8 *)parket_heart,sizeof(parket_heart));
}
void MQTT_WorkClass::MQTT_Disconnect(void)
{
    MQTT_SendBuf((quint8 *)parket_disconnet,sizeof(parket_disconnet));
}
void MQTT_WorkClass::MQTT_SendBuf(quint8 *buf,quint16 len)
{
    if(socket_type)
    {
//        qDebug()<<"len:"<<len;
//        for(int i=0;i<len;i++)
//        {
//            qDebug("%#x ",buf[i]);
//        }
       LocalTcpClientSocket->write((const char *)buf,len);
    }
} 
//客户端模式:创建客户端
void MQTT_WorkClass::ConnectMqttServer(QString ip,quint16 port)
{
    if(LocalTcpClientSocket)
    {
        LocalTcpClientSocket->close();
        delete  LocalTcpClientSocket;
        LocalTcpClientSocket=nullptr;
    }
    /*1. 创建本地客户端TCP套接字*/
    LocalTcpClientSocket = new QTcpSocket;
    /*2. 设置服务器IP地址*/
    QHostAddress FarServerAddr(ip);
    /*3. 连接客户端的信号槽*/
    connect(LocalTcpClientSocket,SIGNAL(connected()),this,SLOT(LocalTcpClientConnectedSlot()));
    connect(LocalTcpClientSocket,SIGNAL(disconnected()),this,SLOT(LocalTcpClientDisconnectedSlot()));
    connect(LocalTcpClientSocket,SIGNAL(readyRead()),this,SLOT(LocalTcpClientReadDtatSlot()));
    connect(LocalTcpClientSocket,SIGNAL(bytesWritten(qint64)),this,SLOT(LocalTcpClientBytesWrittenSlot(qint64)));
    /*4. 尝试连接服务器主机*/
    LocalTcpClientSocket->connectToHost(FarServerAddr,port);
}
void MQTT_WorkClass::Set_MQTT_Addr(QString ip,quint16 port,QString MQTT_ClientID,QString MQTT_UserName,QString MQTT_PassWord)
{
    m_ip=ip;
    m_port=port;
    m_MQTT_ClientID=MQTT_ClientID;
    m_MQTT_UserName=MQTT_UserName;
    m_MQTT_PassWord=MQTT_PassWord;
}
//客户端模式:响应连接上服务器之后的操作
void MQTT_WorkClass::LocalTcpClientConnectedSlot()
{
    socket_type=1;
    //通知外部
    emit MQTT_ConnectState(socket_type);
    //结束事件循环
    EndEvenLoop();
}
//客户端模式:断开服务器
void MQTT_WorkClass::LocalTcpClientDisconnectedSlot()
{
    socket_type=0;
    //通知外部
    emit MQTT_ConnectState(socket_type);
}
//客户端模式:读取服务器发过来的数据
void MQTT_WorkClass::LocalTcpClientReadDtatSlot()
{
   ReadData=LocalTcpClientSocket->readAll();
   qDebug()<<"读取服务器发过来的数据:"<<ReadData.length();
   EndEvenLoop(); //退出事件循环
}
//客户端模式:数据发送成功
void MQTT_WorkClass::LocalTcpClientBytesWrittenSlot(qint64 byte)
{
    LogSend(QString("数据发送成功:%1\n").arg(byte));
    EndEvenLoop(); //退出事件循环
}
//订阅主题
void MQTT_WorkClass::slot_SubscribeTopic(QString topic)
{
    if(MQTT_SubscribeTopic(topic.toUtf8().data(),0,1))
    {
        LogSend(QString("主题订阅失败.\n"));
    }
    else
    {
         LogSend(QString("主题订阅成功.\n"));
    }
}
//发布消息
void MQTT_WorkClass::slot_PublishData(QString topic,QString message)
{
     MQTT_PublishData(topic.toUtf8().data(),message.toUtf8().data(),0);
}
void MQTT_WorkClass::EndEvenLoop()
{
    //停止定时器
    timer->stop();
    //先退出事件循环
    loop.exit();
    //qDebug()<<"退出事件循环";
}
//开始事件循环
void MQTT_WorkClass::StartEvenLoop()
{
    //qDebug()<<"开始事件循环";
    timer->start(5000);
    loop.exec();
}
//断开连接
void MQTT_WorkClass::slot_tcp_close()
{
    if(socket_type)
    {
        timer->stop();
        loop.exit();
        LocalTcpClientSocket->close();
    }
}

4.2 mqtt.h

#ifndef XL_MQTT_H
#define XL_MQTT_H
extern "C"
{
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
}
#include <iostream>
#include <QWidget>
#include <QTcpServer>
#include <QHostInfo>  //获取计算机网络信息
#include <QUdpSocket>
#include <QtNetwork>
#include <QHostInfo>
#include <QDebug>
#include <QTcpSocket>
#include <QHostAddress>
#include <QDebug>
#include <QMessageBox>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QComboBox>
#include <QFile>
#include <QTimer>
#include <QScrollBar>
#define BYTE0(dwTemp)       (*(char *)(&dwTemp))
#define BYTE1(dwTemp)       (*((char *)(&dwTemp) + 1))
#define BYTE2(dwTemp)       (*((char *)(&dwTemp) + 2))
#define BYTE3(dwTemp)       (*((char *)(&dwTemp) + 3))
typedef enum
{
    //名字      值       报文流动方向  描述
    M_RESERVED1 =0  , //  禁止  保留
    M_CONNECT   , //  客户端到服务端 客户端请求连接服务端
    M_CONNACK   , //  服务端到客户端 连接报文确认
    M_PUBLISH   , //  两个方向都允许 发布消息
    M_PUBACK    , //  两个方向都允许 QoS 1消息发布收到确认
    M_PUBREC    , //  两个方向都允许 发布收到(保证交付第一步)
    M_PUBREL    , //  两个方向都允许 发布释放(保证交付第二步)
    M_PUBCOMP   , //  两个方向都允许 QoS 2消息发布完成(保证交互第三步)
    M_SUBSCRIBE   , //  客户端到服务端 客户端订阅请求
    M_SUBACK    , //  服务端到客户端 订阅请求报文确认
    M_UNSUBSCRIBE , //  客户端到服务端 客户端取消订阅请求
    M_UNSUBACK    , //  服务端到客户端 取消订阅报文确认
    M_PINGREQ   , //  客户端到服务端 心跳请求
    M_PINGRESP    , //  服务端到客户端 心跳响应
    M_DISCONNECT  , //  客户端到服务端 客户端断开连接
    M_RESERVED2   , //  禁止  保留
}_typdef_mqtt_message;
class MQTT_WorkClass:public QObject
{
    Q_OBJECT
public:
    QTimer *timer=nullptr;
    MQTT_WorkClass(QObject* parent=nullptr):QObject(parent){}
    ~MQTT_WorkClass();
    //用户名初始化
    void OneNet_LoginInit(char *ProductKey,char *DeviceName,char *DeviceSecret);
    //MQTT协议相关函数声明
    quint8 MQTT_PublishData(char *topic, char *message, quint8 qos);
    quint8 MQTT_SubscribeTopic(char *topic,quint8 qos,quint8 whether);
    void MQTT_Init(void);
    quint8 MQTT_Connect(char *ClientID,char *Username,char *Password);
    void MQTT_SentHeart(void);
    void MQTT_Disconnect(void);
    void MQTT_SendBuf(quint8 *buf,quint16 len);
    void ConnectMqttServer(QString ip,quint16 port);
    void Set_MQTT_Addr(QString ip,quint16 port,QString MQTT_ClientID,QString MQTT_UserName,QString MQTT_PassWord);
    void StartEvenLoop();
public slots:
    void EndEvenLoop();
    void run();
    void LocalTcpClientConnectedSlot();
    void LocalTcpClientDisconnectedSlot();
    void LocalTcpClientReadDtatSlot();
    void LocalTcpClientBytesWrittenSlot(qint64 byte);
    //订阅主题
    void slot_SubscribeTopic(QString topic);
    //发布消息
    void slot_PublishData(QString topic,QString message);
    //断开连接
    void slot_tcp_close();
signals:
    void LogSend(QString text);
    void MQTT_ConnectState(bool state);
private:
    quint8 *mqtt_rxbuf;
    quint8 *mqtt_txbuf;
    quint16 mqtt_rxlen;
    quint16 mqtt_txlen;
    quint8 _mqtt_txbuf[256];//发送数据缓存区
    quint8 _mqtt_rxbuf[256];//接收数据缓存区
    QTcpSocket *LocalTcpClientSocket=nullptr;
    QString m_ip;
    quint16 m_port;
    bool socket_type=0;  //这是网络的状态: 1表示已经连接 0表示未连接
    QString m_MQTT_ClientID;
    QString m_MQTT_UserName;
    QString m_MQTT_PassWord;
    QEventLoop loop;
    QByteArray  ReadData;
};
#endif


相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
6月前
|
机器学习/深度学习 数据库 数据安全/隐私保护
服务器核心组件:CPU 与 GPU 的核心区别、应用场景、协同工作
CPU与GPU在服务器中各司其职:CPU擅长处理复杂逻辑,如订单判断、网页请求;GPU专注批量并行计算,如图像处理、深度学习。二者协同工作,能大幅提升服务器效率,满足多样化计算需求。
2537 39
|
5月前
|
存储 机器学习/深度学习 人工智能
硅谷GPU单节点服务器:技术解析与应用全景
“硅谷GPU单节点服务器”代表了在单个物理机箱内集成强大计算能力,特别是GPU加速能力的高性能计算解决方案。它们并非指代某个特定品牌,而是一类为处理密集型工作负载而设计的服务器范式的统称。
|
8月前
|
弹性计算 关系型数据库 数据库
阿里云服务器ECS是什么?ECS应用场景、租用流程及使用教程整理
阿里云ECS(弹性计算服务)是性能稳定、弹性扩展的云计算服务,支持多种处理器架构和实例类型,适用于网站托管、开发测试、数据存储、企业服务、游戏多媒体及微服务架构等场景。提供从注册、配置到部署、运维的完整使用流程,助力用户高效上云。
|
10月前
|
开发框架 人工智能 Java
破茧成蝶:阿里云应用服务器让传统 J2EE 应用无缝升级 AI 原生时代
本文详细介绍了阿里云应用服务器如何助力传统J2EE应用实现智能化升级。文章分为三部分:第一部分阐述了传统J2EE应用在智能化转型中的痛点,如协议鸿沟、资源冲突和观测失明;第二部分展示了阿里云应用服务器的解决方案,包括兼容传统EJB容器与微服务架构、支持大模型即插即用及全景可观测性;第三部分则通过具体步骤说明如何基于EDAS开启J2EE应用的智能化进程,确保十年代码无需重写,轻松实现智能化跃迁。
745 42
|
9月前
|
存储 分布式计算 安全
阿里云服务器ECS实例选型参考:场景适配、应用推荐
选择阿里云服务器ECS实例之前,需要结合性能、价格、工作负载等因素,做出性价比与稳定性最优的决策。对于很多新手用户来说,在初次购买阿里云服务器的时候,面对众多实例规格往往不知道如何选择,因为云服务器实例规格不同,价格也不一样,性能表现更是千差万别。因此,在购买阿里云服务器ECS实例之前,需要结合性能、价格、工作负载等因素,做出性价比与稳定性最优的决策。本文将通过一些常见的选型场景推荐,为大家详细介绍阿里云服务器实例选型的最佳实践,便于大家在选择云服务器实例规格时做个参考。
|
5月前
|
机器学习/深度学习 人工智能 弹性计算
2025年阿里云GPU服务器租用价格与应用场景详解
阿里云GPU服务器基于ECS架构,集成NVIDIA A10/V100等顶级GPU与自研神龙架构,提供高达1000 TFLOPS混合精度算力。2025年推出万卡级异构算力平台及Aegaeon池化技术,支持AI训练、推理、科学计算与图形渲染,实现性能与成本最优平衡。
|
7月前
|
域名解析 运维 监控
阿里云轻量服务器的系统镜像和应用镜像的区别
轻量应用服务器是阿里云推出的易用型云服务器,支持一键部署、域名解析、安全管理和运维监控。本文介绍其系统镜像与应用镜像的区别及选择建议,助您根据业务需求和技术能力快速决策,实现高效部署。
|
7月前
|
存储 弹性计算 运维
阿里云服务器全解析:ECS是什么、应用场景、租用流程及优缺点分析
阿里云ECS(Elastic Compute Service)是阿里云提供的高性能、高可用的云计算服务,支持弹性扩展、多样化实例类型和多种计费模式。适用于网站搭建、数据处理、运维测试等多种场景,具备分钟级交付、安全可靠、成本低、易运维等优势,是企业及开发者上云的理想选择。
963 5
|
7月前
|
运维 监控 Kubernetes
Bitnami 替代品:Websoft9 如何接力单服务器多应用时代
Bitnami 曾为开源应用部署带来革命性体验,但随着 Docker 成熟与战略转向云原生,其单机多应用支持逐渐弱化。面对多应用管理分散、资源冲突、运维工具缺失等痛点,Websoft9 应运而生,提供一键部署、统一管理、智能调度等能力,全面优化单服务器多应用运维体验,成为 Bitnami 的理想继任者。
267 0
Bitnami 替代品:Websoft9 如何接力单服务器多应用时代

热门文章

最新文章

推荐镜像

更多
  • qt