微信小程序使用stomp.js实现STOMP传输协议的实时聊天

这篇具有很好参考价值的文章主要介绍了微信小程序使用stomp.js实现STOMP传输协议的实时聊天。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介:

stomp.js:uniapp开发的小程序中使用
stomp.js:官网
stomp.js:GitHub

本来使用websocket,后端同事使用了stomp协议,导致前端也需要对应修改。
微信小程序使用stomp.js实现STOMP传输协议的实时聊天,微信小程序,微信小程序,小程序,stomp,websocket,IM,即时通信

如何使用

在static/js中新建stomp.js和websocket.js,然后在需要使用的页面引入监听代码+发送代码即可

代码如下:

位置:项目/pages/static/js/stomp.js
1.stomp.js

// Generated by CoffeeScript 1.7.1

/*
   Stomp Over WebSocket http://www.jmesnil.net/stomp-websocket/doc/ | Apache License V2.0

   Copyright (C) 2010-2013 [Jeff Mesnil](http://jmesnil.net/)
   Copyright (C) 2012 [FuseSource, Inc.](http://fusesource.com)
 */

   (function() {
    var Byte, Client, Frame, Stomp,
      __hasProp = {}.hasOwnProperty,
      __slice = [].slice;
  
    Byte = {
      LF: '\x0A',
      NULL: '\x00'
    };
  
    Frame = (function() {
      var unmarshallSingle;
  
      function Frame(command, headers, body) {
        this.command = command;
        this.headers = headers != null ? headers : {};
        this.body = body != null ? body : '';
      }
  
      Frame.prototype.toString = function() {
        var lines, name, skipContentLength, value, _ref;
        lines = [this.command];
        skipContentLength = this.headers['content-length'] === false ? true : false;
        if (skipContentLength) {
          delete this.headers['content-length'];
        }
        _ref = this.headers;
        for (name in _ref) {
          if (!__hasProp.call(_ref, name)) continue;
          value = _ref[name];
          lines.push("" + name + ":" + value);
        }
        if (this.body && !skipContentLength) {
          lines.push("content-length:" + (Frame.sizeOfUTF8(this.body)));
        }
        lines.push(Byte.LF + this.body);
        return lines.join(Byte.LF);
      };
  
      Frame.sizeOfUTF8 = function(s) {
        if (s) {
          return encodeURI(s).match(/%..|./g).length;
        } else {
          return 0;
        }
      };
  
      unmarshallSingle = function(data) {
        var body, chr, command, divider, headerLines, headers, i, idx, len, line, start, trim, _i, _j, _len, _ref, _ref1;
        divider = data.search(RegExp("" + Byte.LF + Byte.LF));
        headerLines = data.substring(0, divider).split(Byte.LF);
        command = headerLines.shift();
        headers = {};
        trim = function(str) {
          return str.replace(/^\s+|\s+$/g, '');
        };
        _ref = headerLines.reverse();
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          line = _ref[_i];
          idx = line.indexOf(':');
          headers[trim(line.substring(0, idx))] = trim(line.substring(idx + 1));
        }
        body = '';
        start = divider + 2;
        if (headers['content-length']) {
          len = parseInt(headers['content-length']);
          body = ('' + data).substring(start, start + len);
        } else {
          chr = null;
          for (i = _j = start, _ref1 = data.length; start <= _ref1 ? _j < _ref1 : _j > _ref1; i = start <= _ref1 ? ++_j : --_j) {
            chr = data.charAt(i);
            if (chr === Byte.NULL) {
              break;
            }
            body += chr;
          }
        }
        return new Frame(command, headers, body);
      };
  
      Frame.unmarshall = function(datas) {
        var frame, frames, last_frame, r;
        frames = datas.split(RegExp("" + Byte.NULL + Byte.LF + "*"));
        r = {
          frames: [],
          partial: ''
        };
        r.frames = (function() {
          var _i, _len, _ref, _results;
          _ref = frames.slice(0, -1);
          _results = [];
          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            frame = _ref[_i];
            _results.push(unmarshallSingle(frame));
          }
          return _results;
        })();
        last_frame = frames.slice(-1)[0];
        if (last_frame === Byte.LF || (last_frame.search(RegExp("" + Byte.NULL + Byte.LF + "*$"))) !== -1) {
          r.frames.push(unmarshallSingle(last_frame));
        } else {
          r.partial = last_frame;
        }
        return r;
      };
  
      Frame.marshall = function(command, headers, body) {
        var frame;
        frame = new Frame(command, headers, body);
        return frame.toString() + Byte.NULL;
      };
  
      return Frame;
  
    })();
  
    Client = (function() {
      var now;
  
      function Client(ws) {
        this.ws = ws;
        this.ws.binaryType = "arraybuffer";
        this.counter = 0;
        this.connected = false;
        this.heartbeat = {
          outgoing: 10000,
          incoming: 10000
        };
        this.maxWebSocketFrameSize = 16 * 1024;
        this.subscriptions = {};
        this.partialData = '';
      }
  
      Client.prototype.debug = function(message) {
        var _ref;
        return typeof window !== "undefined" && window !== null ? (_ref = window.console) != null ? _ref.log(message) : void 0 : void 0;
      };
  
      now = function() {
        if (Date.now) {
          return Date.now();
        } else {
          return new Date().valueOf;
        }
      };
  
      Client.prototype._transmit = function(command, headers, body) {
        var out;
        out = Frame.marshall(command, headers, body);
        if (typeof this.debug === "function") {
          this.debug(">>> " + out);
        }
        while (true) {
          if (out.length > this.maxWebSocketFrameSize) {
            this.ws.send(out.substring(0, this.maxWebSocketFrameSize));
            out = out.substring(this.maxWebSocketFrameSize);
            if (typeof this.debug === "function") {
              this.debug("remaining = " + out.length);
            }
          } else {
            return this.ws.send(out);
          }
        }
      };
  
      Client.prototype._setupHeartbeat = function(headers) {
        var serverIncoming, serverOutgoing, ttl, v, _ref, _ref1;
        if ((_ref = headers.version) !== Stomp.VERSIONS.V1_1 && _ref !== Stomp.VERSIONS.V1_2) {
          return;
        }
        _ref1 = (function() {
          var _i, _len, _ref1, _results;
          _ref1 = headers['heart-beat'].split(",");
          _results = [];
          for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
            v = _ref1[_i];
            _results.push(parseInt(v));
          }
          return _results;
        })(), serverOutgoing = _ref1[0], serverIncoming = _ref1[1];
        if (!(this.heartbeat.outgoing === 0 || serverIncoming === 0)) {
          ttl = Math.max(this.heartbeat.outgoing, serverIncoming);
          if (typeof this.debug === "function") {
            this.debug("send PING every " + ttl + "ms");
          }
          this.pinger = Stomp.setInterval(ttl, (function(_this) {
            return function() {
              _this.ws.send(Byte.LF);
              return typeof _this.debug === "function" ? _this.debug(">>> PING") : void 0;
            };
          })(this));
        }
        if (!(this.heartbeat.incoming === 0 || serverOutgoing === 0)) {
          ttl = Math.max(this.heartbeat.incoming, serverOutgoing);
          if (typeof this.debug === "function") {
            this.debug("check PONG every " + ttl + "ms");
          }
          return this.ponger = Stomp.setInterval(ttl, (function(_this) {
            return function() {
              var delta;
              delta = now() - _this.serverActivity;
              if (delta > ttl * 2) {
                if (typeof _this.debug === "function") {
                  _this.debug("did not receive server activity for the last " + delta + "ms");
                }
                return _this.ws.close();
              }
            };
          })(this));
        }
      };
  
      Client.prototype._parseConnect = function() {
        var args, connectCallback, errorCallback, headers;
        args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
        headers = {};
        switch (args.length) {
          case 2:
            headers = args[0], connectCallback = args[1];
            break;
          case 3:
            if (args[1] instanceof Function) {
              headers = args[0], connectCallback = args[1], errorCallback = args[2];
            } else {
              headers.login = args[0], headers.passcode = args[1], connectCallback = args[2];
            }
            break;
          case 4:
            headers.login = args[0], headers.passcode = args[1], connectCallback = args[2], errorCallback = args[3];
            break;
          default:
            headers.login = args[0], headers.passcode = args[1], connectCallback = args[2], errorCallback = args[3], headers.host = args[4];
        }
        return [headers, connectCallback, errorCallback];
      };
  
      Client.prototype.connect = function() {
        var args, errorCallback, headers, out;
        args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
        out = this._parseConnect.apply(this, args);
        headers = out[0], this.connectCallback = out[1], errorCallback = out[2];
        if (typeof this.debug === "function") {
          this.debug("Opening Web Socket...");
        }
        this.ws.onmessage = (function(_this) {
          return function(evt) {
            var arr, c, client, data, frame, messageID, onreceive, subscription, unmarshalledData, _i, _len, _ref, _results;
            data = typeof ArrayBuffer !== 'undefined' && evt.data instanceof ArrayBuffer ? (arr = new Uint8Array(evt.data), typeof _this.debug === "function" ? _this.debug("--- got data length: " + arr.length) : void 0, ((function() {
              var _i, _len, _results;
              _results = [];
              for (_i = 0, _len = arr.length; _i < _len; _i++) {
                c = arr[_i];
                _results.push(String.fromCharCode(c));
              }
              return _results;
            })()).join('')) : evt.data;
            _this.serverActivity = now();
            if (data === Byte.LF) {
              if (typeof _this.debug === "function") {
                _this.debug("<<< PONG");
              }
              return;
            }
            if (typeof _this.debug === "function") {
              _this.debug("<<< " + data);
            }
            unmarshalledData = Frame.unmarshall(_this.partialData + data);
            _this.partialData = unmarshalledData.partial;
            _ref = unmarshalledData.frames;
            _results = [];
            for (_i = 0, _len = _ref.length; _i < _len; _i++) {
              frame = _ref[_i];
              switch (frame.command) {
                case "CONNECTED":
                  if (typeof _this.debug === "function") {
                    _this.debug("connected to server " + frame.headers.server);
                  }
                  _this.connected = true;
                  _this._setupHeartbeat(frame.headers);
                  _results.push(typeof _this.connectCallback === "function" ? _this.connectCallback(frame) : void 0);
                  break;
                case "MESSAGE":
                  subscription = frame.headers.subscription;
                  onreceive = _this.subscriptions[subscription] || _this.onreceive;
                  if (onreceive) {
                    client = _this;
                    messageID = frame.headers["message-id"];
                    frame.ack = function(headers) {
                      if (headers == null) {
                        headers = {};
                      }
                      return client.ack(messageID, subscription, headers);
                    };
                    frame.nack = function(headers) {
                      if (headers == null) {
                        headers = {};
                      }
                      return client.nack(messageID, subscription, headers);
                    };
                    _results.push(onreceive(frame));
                  } else {
                    _results.push(typeof _this.debug === "function" ? _this.debug("Unhandled received MESSAGE: " + frame) : void 0);
                  }
                  break;
                case "RECEIPT":
                  _results.push(typeof _this.onreceipt === "function" ? _this.onreceipt(frame) : void 0);
                  break;
                case "ERROR":
                  _results.push(typeof errorCallback === "function" ? errorCallback(frame) : void 0);
                  break;
                default:
                  _results.push(typeof _this.debug === "function" ? _this.debug("Unhandled frame: " + frame) : void 0);
              }
            }
            return _results;
          };
        })(this);
        this.ws.onclose = (function(_this) {
          return function() {
            var msg;
            msg = "Whoops! Lost connection to " + _this.ws.url;
            if (typeof _this.debug === "function") {
              _this.debug(msg);
            }
            _this._cleanUp();
            return typeof errorCallback === "function" ? errorCallback(msg) : void 0;
          };
        })(this);
        return this.ws.onopen = (function(_this) {
          return function() {
            if (typeof _this.debug === "function") {
              _this.debug('Web Socket Opened...');
            }
            headers["accept-version"] = Stomp.VERSIONS.supportedVersions();
            headers["heart-beat"] = [_this.heartbeat.outgoing, _this.heartbeat.incoming].join(',');
            return _this._transmit("CONNECT", headers);
          };
        })(this);
      };
  
      Client.prototype.disconnect = function(disconnectCallback, headers) {
        if (headers == null) {
          headers = {};
        }
        this._transmit("DISCONNECT", headers);
        this.ws.onclose = null;
        this.ws.close();
        this._cleanUp();
        return typeof disconnectCallback === "function" ? disconnectCallback() : void 0;
      };
  
      Client.prototype._cleanUp = function() {
        this.connected = false;
        if (this.pinger) {
          Stomp.clearInterval(this.pinger);
        }
        if (this.ponger) {
          return Stomp.clearInterval(this.ponger);
        }
      };
  
      Client.prototype.send = function(destination, headers, body) {
        if (headers == null) {
          headers = {};
        }
        if (body == null) {
          body = '';
        }
        headers.destination = destination;
        return this._transmit("SEND", headers, body);
      };
  
      Client.prototype.subscribe = function(destination, callback, headers) {
        var client;
        if (headers == null) {
          headers = {};
        }
        if (!headers.id) {
          headers.id = "sub-" + this.counter++;
        }
        headers.destination = destination;
        this.subscriptions[headers.id] = callback;
        this._transmit("SUBSCRIBE", headers);
        client = this;
        return {
          id: headers.id,
          unsubscribe: function() {
            return client.unsubscribe(headers.id);
          }
        };
      };
  
      Client.prototype.unsubscribe = function(id) {
        delete this.subscriptions[id];
        return this._transmit("UNSUBSCRIBE", {
          id: id
        });
      };
  
      Client.prototype.begin = function(transaction) {
        var client, txid;
        txid = transaction || "tx-" + this.counter++;
        this._transmit("BEGIN", {
          transaction: txid
        });
        client = this;
        return {
          id: txid,
          commit: function() {
            return client.commit(txid);
          },
          abort: function() {
            return client.abort(txid);
          }
        };
      };
  
      Client.prototype.commit = function(transaction) {
        return this._transmit("COMMIT", {
          transaction: transaction
        });
      };
  
      Client.prototype.abort = function(transaction) {
        return this._transmit("ABORT", {
          transaction: transaction
        });
      };
  
      Client.prototype.ack = function(messageID, subscription, headers) {
        if (headers == null) {
          headers = {};
        }
        headers["message-id"] = messageID;
        headers.subscription = subscription;
        return this._transmit("ACK", headers);
      };
  
      Client.prototype.nack = function(messageID, subscription, headers) {
        if (headers == null) {
          headers = {};
        }
        headers["message-id"] = messageID;
        headers.subscription = subscription;
        return this._transmit("NACK", headers);
      };
  
      return Client;
  
    })();
  
    Stomp = {
      VERSIONS: {
        V1_0: '1.0',
        V1_1: '1.1',
        V1_2: '1.2',
        supportedVersions: function() {
          return '1.1,1.0';
        }
      },
      client: function(url, protocols) {
        var klass, ws;
        if (protocols == null) {
          protocols = ['v10.stomp', 'v11.stomp'];
        }
        klass = Stomp.WebSocketClass || WebSocket;
        ws = new klass(url, protocols);
        return new Client(ws);
      },
      over: function(ws) {
        return new Client(ws);
      },
      Frame: Frame
    };
  
    if (typeof exports !== "undefined" && exports !== null) {
      exports.Stomp = Stomp;
    }
  
    if (typeof window !== "undefined" && window !== null) {
      Stomp.setInterval = function(interval, f) {
        return window.setInterval(f, interval);
      };
      Stomp.clearInterval = function(id) {
        return window.clearInterval(id);
      };
      window.Stomp = Stomp;
    } else if (!exports) {
      self.Stomp = Stomp;
    }
  
  }).call(this);

位置:项目/pages/static/js/websocket.js
2.websocket.js

const Stomp = require('./stomp.js').Stomp;

let socketOpen = false
let socketMsgQueue = []

export default {
  client: null,
  init(url, header ,connectWS) {
    if (this.client) {
      return Promise.resolve(this.client)
    }

    return new Promise((resolve, reject) => {
      const ws = {
        send: this.sendMessage,
        onopen: null,
        onmessage: null
      }

      wx.connectSocket({ url, header })

      wx.onSocketOpen(function (res) {
        console.log('WebSocket连接已打开!', res)

        socketOpen = true
        for (let i = 0; i < socketMsgQueue.length; i++) {
          ws.send(socketMsgQueue[i])
        }
        socketMsgQueue = []

        ws.onopen && ws.onopen()
      })

      wx.onSocketMessage(function (res) {
      	// ios 缺少 0x00 导致解析失败
        if (res && res.data) {
          let value = res.data;
          let code = value.charCodeAt(value.length - 1);
          if (code !== 0x00) {
            value += String.fromCharCode(0x00);
            res.data = value;
          }
        }
        ws.onmessage && ws.onmessage(res)
      })

      wx.onSocketError(function (res) {
        console.log('WebSocket 错误!', res)
      })

      wx.onSocketClose((res) => {
        this.client = null
        socketOpen = false
        console.log('WebSocket 已关闭!', res)
        if(res.code !== 1000){
          setTimeout(()=>{
            connectWS()
          },3000)
        }
      })

      Stomp.setInterval = function (interval, f) {
        return setInterval(f, interval)
      }
      Stomp.clearInterval = function (id) {
        return clearInterval(id)
      }

      const client = (this.client = Stomp.over(ws))
      // 关闭连接
      client.close = () =>{
        wx.closeSocket()
      }
      client.connect(header, function () {
        console.log('stomp connected')
        resolve(client)
      })
    })
  },
  sendMessage(message) {
    if (socketOpen) {
      wx.sendSocketMessage({
        data: message,
      })
    } else {
      socketMsgQueue.push(message)
    }
  },
}

3.监听+发送代码文章来源地址https://www.toymoban.com/news/detail-680991.html

import WebSocket from "../../static/js/websocket"
const app = getApp();
data: {
	objUid: '1',
	client: null,
	content: '发送的内容',
	subscription:''
},
onLoad(options) {
	// stomp协议请求 
	this.initWS()
},
onShow() {
    // 切换任务后台,ws断开后重连
    if(!WebSocket.client){
        this.initWS()
    }
},
onUnload() {
	// 不关闭websocket连接,但是断开订阅
	this.data.subscription && this.data.subscription.unsubscribe(this.data.subscription.id)
	// 直接关闭websocket
	// this.data.client && this.data.client.close()
},
initWS() {
	WebSocket.init(
		`${app.globalData.WSURL}/chat`,
		// 传参
		{
			// login: 'admin',
			// passcode: 'admin',
		},
		// ws断开回调
		() => {
			this.initWS()
		}
	).then((client) => {
		this.setData({
			client: client
		})
		// 订阅
		const subscription = client.subscribe(
			// 路径
			`/response/${app.globalData.uid}/${this.data.objUid}`,
			// 接收到的数据
			(res) => {
				console.log(res)
			},
			// 消息不会被确认接收,不确认每次连接都会推送
			// { ack: 'client' } 
		)
		this.setData({
	        subscription: subscription
	    })
	})
},
// 直接调用发送即可
send() {
	this.data.client.send(
		// 路径
		`/child/${app.globalData.uid}/${this.data.objUid}`,
		// 自定义参数 http://jmesnil.net/stomp-websocket/doc/
		{},//priority: 9 
		// 发送文本
		JSON.stringify({ 'content': this.data.content })
	);
},

到了这里,关于微信小程序使用stomp.js实现STOMP传输协议的实时聊天的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于SockJS+Stomp的WebSocket实现

    前言     之前做个一个功能,通过websocket长链接接收后台推送的数据,然后在前端动态渲染。一直没来的及输出个文档,现在输出一下。 WebSocket介绍     WebSocket 是一种在 Web 应用中实现实时通信的方法,它可以在客户端和服务器端之间建立长连接,实现实时消息传递。  

    2024年02月12日
    浏览(36)
  • 整合 WebSocket 基于 STOMP 协议实现广播

    SpringBoot 实战 (十六) | 整合 WebSocket 基于 STOMP 协议实现广播 如题,今天介绍的是 SpringBoot 整合 WebSocket 实现广播消息。 什么是 WebSocket ? WebSocket 为浏览器和服务器提供了双工异步通信的功能,即浏览器可以向服务器发送信息,反之也成立。 WebSocket 是通过一个 socket 来实现双

    2024年01月21日
    浏览(52)
  • java中使用sockjs、stomp完成websocket通信

    主要配置 握手拦截(这套方案好像前端无法补充Header,就不在这里做权限校验)这里采用的方法是直接问号拼接token,前端 new SockJS(这里带问号),sockjs使用的是http所以没毛病,本文使用的是OAuth2权限校验 之后可以设置握手之后的身份注入(配置了这个可以在单对单订阅时直接使用) 储

    2024年02月10日
    浏览(34)
  • 使用Flask+OpenCV实现浏览器/微信小程序的视频流传输

    前言 一、 Flask+浏览器实现 二、 Flask+微信小程序实现 三、Flask+uni-app小程序实现 后记 近期在做的东西涉及到实时视频的处理,碰到一些问题,因此将之记录下来,便于日后翻看,同时也希望能给遇到同样问题的小伙伴提供帮助。 实现代码如下: 分为 app.py 和index.html。 1. F

    2024年02月06日
    浏览(69)
  • Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)(1)

    server: port: 9908 3.WebSocketConfig.java import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springfra

    2024年04月25日
    浏览(44)
  • Springboot 整合 WebSocket ,使用STOMP协议+Redis 解决负载场景问题

    ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jacksonSeial.setObjectMapper(om); template.setValueSerializer(jacksonSeial); template.setKeySerializer(stringRedisSerializer); template.setHashKeySerializer(stringRedisSerializer); template

    2024年04月14日
    浏览(52)
  • Spring Boot 3 + Vue 3 整合 WebSocket (STOMP协议) 实现广播和点对点实时消息

    🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall 🍃 vue3-element-admin 🍃 youlai-boot 🌺 仓库主页: Gitee 💫 Github 💫 GitCode 💖 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请纠正! WebSocket是一种在Web浏览器与Web服务器之间建立双向通信的协议,而Spring Boot提供了便捷的WebSocket支持

    2024年02月02日
    浏览(48)
  • websocket + stomp + sockjs学习

    Spring WebSocket整合Stomp源码详解 PDF版本 Spring SpringBoot官方文档资料 spring5.1.9官方文档关于websocket的介绍 spring5.3.29官方文档关于websocket的介绍 WebSocket入门教程示例代码,代码地址已fork至本地gitee,原github代码地址,源老外的代码地址 [WebSocket入门]手把手搭建WebSocket多人在线聊天

    2024年02月12日
    浏览(32)
  • WebSocket—STOMP详解(官方原版)

    WebSocket协议定义了两种类型的消息(文本和二进制),但其内容未作定义。该协议定义了一种机制,供客户端和服务器协商在WebSocket之上使用的子协议(即更高级别的消息传递协议),以定义各自可以发送何种消息、格式是什么、每个消息的内容等等。子协议的使用是可选的

    2024年02月04日
    浏览(39)
  • 全双工通信协议:WebSockets+STOMP

    WebSocket 协议定义了两种类型的消息(文本和二进制),但是它们的内容是未定义的。 STOMP (Streaming Text Oriented Messaging Protocol)是一种简单的、基于文本的消息传递协议,提供了一组命令和消息格式,用于在客户端和服务端之间发送和接收消息。客户端可以通过连接到消息代理(

    2024年02月20日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包