Connect to MQTT server using WebSocket

In recent years, with the rapid development of Web front-end, new features of browsers emerge one after another, and more and more applications can be implemented on the browser side through the browser rendering engine.

WebSocket is a protocol for full-duplex communication over a single TCP connection. The WebSocket communication protocol was standardized by the IETF in 2011 as standard RFC 6455 and supplemented by RFC 7936. The WebSocket API is also standardized by the W3C.

WebSocket makes data exchange between client and server easier, allowing the server to actively push data to the client. In the WebSocket API, the browser and the server only need to complete a handshake, and a persistent connection can be created directly between the two, and two-way data transmission can be performed. ^1

Chapter 6 of the MQTT protocol specifies the conditions that MQTT needs to meet for transmission over a WebSocket [RFC6455] connection, and the content of the protocol is not described in detail here.

Comparing the two clients

Paho.mqtt.js

Paho is an MQTT client project for Eclipse, and Paho JavaScript Client is one of the browser-based libraries that uses WebSockets to connect to an MQTT server. Compared to another JavaScript linking library, it has fewer features and is not recommended.

MQTT.js

MQTT.js is a completely open source MQTT protocol client library, written in JavaScript, available for Node.js and browsers. On the Node.js side, you can use the command line connection through global installation, and support MQTT/TCP, MQTT/TLS, MQTT/WebSocket connections; it is worth mentioning that MQTT.js also has better support for WeChat applet.

This article will use the MQTT.js library to explain the WebSocket connection.

Install MQTT.js

If the Node.js runtime environment is installed on the reader's machine, you can directly use the npm command to install MQTT.js.

Install in the current directory

npm install mqtt --save

CDN reference

Or use the CDN address directly without installation

<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>

<script>
    // 将在全局初始化一个 mqtt 变量
    console.log(mqtt)
</script>

Connect to MQTT server

This article will use the free EMQ X, which is based on EMQ X's MQTT IoT cloud platform . The server access information is as follows:

  • Broker: broker.emqx.io
  • TCP Port: 1883
  • Websocket Port: 8083

EMQ X uses port 8083 for normal connections and 8084 for WebSocket connections over SSL.

For simplicity, let's put subscribers and publishers in the same file:

const clientId = 'mqttjs_' + Math.random().toString(16).substr(2, 8)

const host = 'ws://broker.emqx.io:8083/mqtt'

const options = {
  keepalive: 60,
  clientId: clientId,
  protocolId: 'MQTT',
  protocolVersion: 4,
  clean: true,
  reconnectPeriod: 1000,
  connectTimeout: 30 * 1000,
  will: {
    topic: 'WillMsg',
    payload: 'Connection Closed abnormally..!',
    qos: 0,
    retain: false
  },
}

console.log('Connecting mqtt client')
const client = mqtt.connect(host, options)

client.on('error', (err) => {
  console.log('Connection error: ', err)
  client.end()
})

client.on('reconnect', () => {
  console.log('Reconnecting...')
})

connection address

The connection address demonstrated above can be split into: ws:// broker. emqx.io:8083 /mqtt

i.e. 协议// 主机名. 域名: 端口/路径

Beginners are prone to the following mistakes:

  • The connection address does not specify the protocol: WebSocket as a communication protocol uses ws(unencrypted), wss (SSL encrypted) as the protocol identifier. The MQTT.js client supports multiple protocols, and the connection address needs to specify the protocol type;
  • The connection address does not specify the port: MQTT does not specify the WebSocket access port. By default 8083 8084, as the unencrypted connection port and the encrypted connection port. The default port of the WebSocket protocol is the same as HTTP (80/443). If you do not fill in the port, it means that the default port of WebSocket is used to connect; and when using standard MQTT connection, you do not need to specify the port. For example, MQTT.js can use the mqtt://localhostconnection To the standard MQTT 1883 port, when the connection address is mqtts://localhost, it connects to the 8884 port;
  • There is no path for the connection address: MQTT-WebSoket is used uniformly /pathas the connection path. When connecting, it needs to be specified. The path used on EMQ X is /mqtt;
  • Protocol does not match port: wssconnection is but connected to 8083port;
  • Use unencrypted WebSocket connections under HTTPS: While promoting HTTPS, organizations such as Google have also implemented security restrictions through browser constraints, that is, under HTTPS connections, browsers will automatically prohibit the use of unencrypted wsprotocols to initiate connection requests;
  • The certificate does not match the connection address: The length is long. For details, see EMQ Enable SSL/TLS Encrypted Connection below .

Connection options

In the above code, it optionsis the client connection option. The following is the description of the main parameters. Please refer to https://www.npmjs.com/package/mqtt#connect for the rest of the parameters .

  • keepalive: heartbeat time, the default is 60 seconds, set 0 to disable;
  • clientId: client ID, which is 'mqttjs_' + Math.random().toString(16).substr(2, 8)randomly ;
  • username: connection username (optional);
  • password: connection password (optional);
  • clean: true, set to false to receive QoS 1 and 2 messages when offline;
  • reconnectPeriod: The default is 1000 milliseconds, the interval between two reconnects, the client will reconnect if the client ID is repeated, the authentication fails, etc.;
  • connectTimeout: The default is 30 * 1000 milliseconds, the time to wait before receiving CONNACK, that is, the connection timeout time;
  • will: Will message, a message that the Broker will automatically send when the client is severely disconnected. The general format is:
    • topic: the topic to publish
    • payload: the message to publish
    • qos:QoS
    • retain: retain flag

SUBSCRIBE/UNSUBSCRIBE

Subscription can only be done after the connection is successful, and the subscribed topic must conform to the MQTT subscription topic rules;

Pay attention to the asynchronous and non-blocking nature of JavaScript. Only after the connect event can you ensure that the client has successfully connected, or client.connectedjudge :

client.on('connect', () => {
  console.log('Client connected:' + clientId)
  // Subscribe
  client.subscribe('testtopic', { qos: 0 })
})
// Unsubscribe
client.unubscribe('testtopic', () => {
  console.log('Unsubscribed')
})

post/receive message

To publish a message to a topic, the published topic must conform to the MQTT publishing topic rules, otherwise the connection will be disconnected. There is no need to subscribe to the topic before publishing, but make sure clients have successfully connected:

// Publish
client.publish('testtopic', 'ws connection demo...!', { qos: 0, retain: false })
// Received
client.on('message', (topic, message, packet) => {
  console.log('Received Message: ' + message.toString() + '\nOn topic: ' + topic)
})

WeChat applet

The MQTT.js library handles WeChat Mini Programs specially, using the wxsprotocol identifier. Note that the Mini Program development specification requires that an encrypted connection must be used, and the connection address should be similar to wxs://broker.emqx.io:8084/mqtt.

EMQ X enables SSL/TLS encrypted connection

EMQ has a built-in self-signed certificate, and the encrypted WebSocket connection has been started by default, but most browsers will report an invalid certificate error, such as net::ERR_CERT_COMMON_NAME_INVALID(Chrome, 360 and other webkit kernel browsers are in developer mode, the Console tab can view most connection errors ). The reason for this error is that the browser cannot verify the validity of the self-signed certificate. The reader needs to purchase a trusted certificate from a certificate authority, and refer to the corresponding section in this article for configuration operations: EMQ X MQTT server enables SSL/TLS security connect .

Here is a summary of the conditions required to enable SSL/TLS certificates:

  • Bind the domain name to the public address of the MQTT server: the signature of the certificate issued by the CA is for the domain name;
  • Apply for a certificate: apply for the certificate of the domain name used from the CA agency, pay attention to choose a reliable CA agency and the certificate should distinguish between the generic domain name and the host name;
  • When using an encrypted connection, select the wssprotocol and use the domain name to connect : After binding the domain name-certificate, you must use the domain name instead of the IP address to connect, so that the browser will verify the certificate according to the domain name to establish a connection after passing the verification.

EMQ X configuration

Open the etc/emqx.confconfiguration file and modify the following configuration:

# wss 监听地址
listener.wss.external = 8084

# 修改密钥文件地址
listener.wss.external.keyfile = etc/certs/cert.key

# 修改证书文件地址
listener.wss.external.certfile = etc/certs/cert.pem

After completion, restart EMQ X.

You can replace it directly under etc/certs/ with your certificate and key files.

Configure reverse proxy and certificate on Nginx

Using Nginx to reverse proxy and encrypt WebSocket can reduce the computing pressure of EMQ X server, realize domain name reuse, and distribute multiple back-end service entities through Nginx's load balancing.

# 建议 WebSocket 也绑定到 443 端口
listen 443, 8084;
server_name example.com;

ssl on;

ssl_certificate /etc/cert.crt;  # 证书路径
ssl_certificate_key /etc/cert.key; # 密钥路径


# upstream 服务器列表
upstream emq_server {
    server 10.10.1.1:8883 weight=1;
    server 10.10.1.2:8883 weight=1;
    server 10.10.1.3:8883 weight=1;
}

# 普通网站应用
location / {
    root www;
    index index.html;
}

# 反向代理到 EMQ X 非加密 WebSocket
location / {
    proxy_redirect off;
    # upstream
    proxy_pass http://emq_server;
    
    proxy_set_header Host $host;
    # 反向代理保留客户端地址
    proxy_set_header X-Real_IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
    # WebSocket 额外请求头
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection “upgrade”;
}

Other resources

See the complete code of the project: https://github.com/emqx/MQTT-Client-Examples/tree/master/mqtt-client-WebSocket

An online MQTT WebSocket connection test tool: https://www.emqx.io/cn/mqtt/mqtt-websocket-toolkit

Copyright statement: This article is EMQ original

Original link: https://www.emqx.io/cn/blog/connect-to-mqtt-broker-with-websocket

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324140099&siteId=291194637