10-1. 即時通訊協定概覽

認識 MQTT、XMPP、STOMP、AMQP 等協定的特性與應用場景

📨 即時通訊協定概覽

🎯 什麼是即時通訊協定?

想像一個郵局系統,有不同的郵寄方式:

  • 平信:HTTP,寄出去就不管了,沒有回執
  • 掛號信:有送達確認,但比較慢
  • 快遞:專人配送,可以即時追蹤
  • 郵政信箱:訂閱制,有新信就通知

即時通訊協定就像這些不同的郵寄方式,針對不同需求設計出不同的訊息傳遞機制。

🏗️ 常見的即時通訊協定

1️⃣ MQTT (Message Queuing Telemetry Transport)

特性:輕量級、低頻寬、低功耗

💡 比喻:訂閱制報紙
你訂閱了「體育版」,報社有新的體育新聞就會自動送到你家
不需要你每天去報社問「有新聞嗎?」

適用場景:

  • ⚡ IoT 物聯網裝置(智慧家居、感測器)
  • 📱 行動裝置(省電、省流量)
  • 🌐 網路不穩定環境

架構:發布/訂閱模式(Pub/Sub)

Publisher → Broker → Subscriber

裝置 A 發布 "temperature/living-room" = 25°C
裝置 B 訂閱 "temperature/#" → 收到通知

Python 範例:

import paho.mqtt.client as mqtt

# 訂閱者
def on_connect(client, userdata, flags, rc):
    print("連接成功")
    client.subscribe("home/temperature")  # 訂閱溫度主題

def on_message(client, userdata, msg):
    print(f"收到訊息:{msg.topic} = {msg.payload.decode()}")

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.connect("mqtt.example.com", 1883, 60)
client.loop_forever()
# 發布者
import paho.mqtt.client as mqtt

client = mqtt.Client()
client.connect("mqtt.example.com", 1883, 60)

# 發布溫度資訊
client.publish("home/temperature", "25.5")
client.disconnect()

2️⃣ XMPP (Extensible Messaging and Presence Protocol)

特性:開放、可擴展、即時

💡 比喻:即時通訊 App(LINE、WhatsApp)
可以傳文字、圖片、知道對方是否在線
還能建立群組、視訊通話

適用場景:

  • 💬 即時聊天應用
  • 👥 社交平台
  • 🎮 線上遊戲(顯示玩家在線狀態)

特點:

  • ✅ 分散式架構(不依賴單一伺服器)
  • ✅ 支援線上狀態(Presence)
  • ✅ 端對端加密
  • ✅ XML 格式(可讀性高但較占頻寬)

訊息格式:

<message to="user@example.com" from="alice@example.com" type="chat">
  <body>Hello, how are you?</body>
</message>

Python 範例:

import slixmpp

class MyBot(slixmpp.ClientXMPP):
    def __init__(self, jid, password):
        super().__init__(jid, password)

        # 註冊事件處理器
        self.add_event_handler("session_start", self.start)
        self.add_event_handler("message", self.message)

    async def start(self, event):
        self.send_presence()  # 發送線上狀態
        await self.get_roster()  # 獲取聯絡人列表

    async def message(self, msg):
        if msg['type'] in ('chat', 'normal'):
            print(f"收到訊息:{msg['body']}")
            msg.reply(f"你說:{msg['body']}").send()

# 使用
bot = MyBot('user@example.com', 'password')
bot.connect()
bot.process(forever=True)

3️⃣ STOMP (Simple Text Oriented Messaging Protocol)

特性:簡單、文字導向、易於實作

💡 比喻:簡化版的郵局系統
規則簡單明瞭,任何人都能快速上手
不像 AMQP 那麼複雜專業

適用場景:

  • 🌐 Web 應用程式
  • 🔄 訊息佇列
  • 📊 即時數據推送

訊息格式:

SEND
destination:/queue/test
content-type:text/plain

Hello, STOMP!^@

JavaScript + Node.js 範例:

// 前端(瀏覽器)
const client = new StompJs.Client({
    brokerURL: 'ws://localhost:15674/ws',
    onConnect: () => {
        console.log('連接成功');

        // 訂閱訊息
        client.subscribe('/topic/notifications', (message) => {
            console.log('收到通知:', message.body);
        });

        // 發送訊息
        client.publish({
            destination: '/topic/notifications',
            body: 'Hello from client!'
        });
    }
});

client.activate();
// 後端(Node.js + RabbitMQ)
const amqp = require('amqplib');

async function setupStomp() {
    const connection = await amqp.connect('amqp://localhost');
    const channel = await connection.createChannel();

    // 宣告交換機
    await channel.assertExchange('notifications', 'topic', { durable: false });

    // 訂閱訊息
    const q = await channel.assertQueue('', { exclusive: true });
    await channel.bindQueue(q.queue, 'notifications', '#');

    channel.consume(q.queue, (msg) => {
        console.log('收到訊息:', msg.content.toString());
    }, { noAck: true });
}

setupStomp();

4️⃣ AMQP (Advanced Message Queuing Protocol)

特性:企業級、可靠、功能完整

💡 比喻:專業物流公司(順豐、DHL)
提供各種配送選項:標準、快速、保價
保證不會遺失、可以追蹤、支援退件

適用場景:

  • 🏢 企業級應用
  • 💼 金融交易系統
  • 📦 訂單處理系統
  • 🔄 微服務架構

核心概念:

Producer → Exchange → Queue → Consumer

Exchange 類型:
1. Direct:精確匹配 routing key
2. Topic:萬用字元匹配(*.error、log.#)
3. Fanout:廣播給所有佇列
4. Headers:根據 headers 屬性路由

Python 範例(使用 RabbitMQ):

import pika

# 生產者
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

# 宣告交換機和佇列
channel.exchange_declare(exchange='logs', exchange_type='fanout')
channel.queue_declare(queue='task_queue', durable=True)
channel.queue_bind(exchange='logs', queue='task_queue')

# 發送訊息(持久化)
channel.basic_publish(
    exchange='logs',
    routing_key='',
    body='Important task',
    properties=pika.BasicProperties(
        delivery_mode=2,  # 訊息持久化
    )
)

print("訊息已發送")
connection.close()
# 消費者
def callback(ch, method, properties, body):
    print(f"收到任務:{body.decode()}")
    # 處理任務...
    ch.basic_ack(delivery_tag=method.delivery_tag)  # 確認處理完成

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

channel.queue_declare(queue='task_queue', durable=True)

# 設定 QoS:一次只處理一個訊息
channel.basic_qos(prefetch_count=1)

channel.basic_consume(
    queue='task_queue',
    on_message_callback=callback,
    auto_ack=False  # 手動確認
)

print('等待訊息...')
channel.start_consuming()

📊 協定比較表

協定傳輸模式訊息格式複雜度QoS適用場景
MQTTPub/Sub二進位簡單✅ 3種IoT、行動裝置
XMPP點對點/群組XML中等即時聊天、社交
STOMPPub/Sub/Queue文字簡單Web 應用
AMQPQueue/Pub/Sub二進位複雜企業級應用

🔍 如何選擇協定?

使用 MQTT 當你需要:

  • IoT 裝置通訊(智慧家居、感測器)
  • 📱 行動裝置(省電、省流量)
  • 🌐 網路不穩定環境
  • 🔔 訂閱制推送通知

使用 XMPP 當你需要:

  • 💬 即時聊天功能
  • 👤 線上狀態顯示(在線/離線/忙碌)
  • 🔐 端對端加密
  • 🌍 分散式架構(不依賴單一伺服器)

使用 STOMP 當你需要:

  • 🌐 Web 應用即時通訊
  • 🚀 快速開發原型
  • 📝 簡單易懂的協定
  • 🔧 與 WebSocket 整合

使用 AMQP 當你需要:

  • 🏢 企業級可靠性
  • 💰 金融交易系統
  • 📦 複雜路由需求
  • 🔄 微服務通訊
  • 訊息持久化和確認機制

🎓 實際應用案例

案例 1:智慧家居系統(MQTT)

# 溫度感測器發布數據
client.publish("home/living-room/temperature", "25.5")
client.publish("home/bedroom/temperature", "23.0")

# 空調訂閱溫度,自動調節
client.subscribe("home/+/temperature")  # + 萬用字元匹配任何房間

案例 2:即時聊天 App(XMPP)

# 發送訊息 + 顯示對方狀態
await bot.send_message(
    mto="friend@example.com",
    mbody="Hey, are you free?",
    mtype="chat"
)

# 設定自己的狀態
bot.send_presence(pshow="away", pstatus="In a meeting")

案例 3:電商訂單系統(AMQP)

# 訂單服務發送新訂單
channel.basic_publish(
    exchange='orders',
    routing_key='order.created',
    body=json.dumps({
        'order_id': '12345',
        'user_id': 'user_001',
        'total': 1500
    })
)

# 庫存服務訂閱並處理
channel.queue_bind(exchange='orders', queue='inventory', routing_key='order.*')

# 通知服務發送 Email
channel.queue_bind(exchange='orders', queue='notifications', routing_key='order.*')

🔐 安全性考量

1. 傳輸加密

# MQTT over TLS
client = mqtt.Client()
client.tls_set(ca_certs="ca.crt", certfile="client.crt", keyfile="client.key")
client.connect("mqtt.example.com", 8883)

# AMQP over SSL
connection = pika.BlockingConnection(
    pika.ConnectionParameters(
        host='localhost',
        port=5671,
        ssl_options=pika.SSLOptions(context)
    )
)

2. 身份驗證

# MQTT 使用者名稱/密碼
client.username_pw_set("username", "password")

# AMQP 身份驗證
credentials = pika.PlainCredentials('user', 'pass')
connection = pika.BlockingConnection(
    pika.ConnectionParameters(host='localhost', credentials=credentials)
)

3. 訊息完整性

# AMQP 訊息簽章
import hmac
import hashlib

def sign_message(message, secret_key):
    signature = hmac.new(
        secret_key.encode(),
        message.encode(),
        hashlib.sha256
    ).hexdigest()
    return {'message': message, 'signature': signature}

# 發送簽章訊息
signed = sign_message('Important data', 'secret')
channel.basic_publish(exchange='', routing_key='queue', body=json.dumps(signed))

🎯 常見面試題

Q1:MQTT 的 QoS 等級有哪些?

答案:

MQTT 提供 3 種 QoS(Quality of Service)等級:

  1. QoS 0(At most once):最多一次

    • 發送即忘,不確認
    • 類似 UDP
    • 最快但可能遺失
  2. QoS 1(At least once):至少一次

    • 確保送達,但可能重複
    • 需要 PUBACK 確認
  3. QoS 2(Exactly once):恰好一次

    • 保證送達且不重複
    • 四次握手(PUBREC → PUBREL → PUBCOMP)
    • 最可靠但最慢

口訣:「零忘一重二恰好」(0=遺忘、1=重複、2=恰好)

# 使用不同 QoS
client.publish("topic", "message", qos=0)  # 最快
client.publish("topic", "message", qos=1)  # 平衡
client.publish("topic", "message", qos=2)  # 最可靠

Q2:AMQP 和 MQTT 的主要差異?

答案:

特性AMQPMQTT
設計目標企業級訊息佇列IoT 輕量通訊
複雜度高(支援多種交換機類型)低(簡單 Pub/Sub)
訊息路由複雜(Direct/Topic/Fanout/Headers)簡單(Topic 層級)
訊息保證持久化、事務、確認QoS 0/1/2
頻寬需求較高極低(2 bytes header)
適用場景金融、訂單處理感測器、行動裝置

記憶技巧:

  • AMQP = Advanced(進階企業用)
  • MQTT = Minimal(最小物聯網用)

Q3:什麼是 Pub/Sub 模式?與點對點模式有何不同?

答案:

Pub/Sub(發布/訂閱):

一對多,發布者不知道誰會收到

報社(Publisher)→ 報紙(Topic)→ 訂閱者們(Subscribers)

- 報社發布新聞,不知道誰訂閱
- 訂閱者可以隨時加入/退出
- 一則新聞可以被多人看到

Point-to-Point(點對點):

一對一,訊息只能被一個消費者處理

寄信人 → 信箱(Queue)→ 收信人

- 每封信只有一個收件人
- 信被取走後就沒了
- 適合任務分配

程式碼比較:

# Pub/Sub(MQTT)
client.publish("news/sports", "Team A wins!")  # 所有訂閱者都收到

# Point-to-Point(AMQP Queue)
channel.basic_publish(exchange='', routing_key='tasks', body='Task 1')
# 只有一個 worker 會處理

Q4:如何保證訊息不遺失?

答案:

多層保護機制:

  1. 傳輸層保證(QoS)
# MQTT QoS 2:保證送達且不重複
client.publish("critical/data", payload, qos=2)
  1. 持久化(Persistence)
# AMQP 訊息持久化
channel.basic_publish(
    exchange='',
    routing_key='task_queue',
    body='Important task',
    properties=pika.BasicProperties(
        delivery_mode=2,  # 持久化到硬碟
    )
)

# 佇列持久化
channel.queue_declare(queue='task_queue', durable=True)
  1. 手動確認(Manual ACK)
def callback(ch, method, properties, body):
    print(f"處理:{body}")
    # 處理完成後才確認
    ch.basic_ack(delivery_tag=method.delivery_tag)

channel.basic_consume(
    queue='task_queue',
    on_message_callback=callback,
    auto_ack=False  # 手動確認
)
  1. 重試機制
# 死信佇列(Dead Letter Queue)
channel.queue_declare(
    queue='main_queue',
    arguments={
        'x-dead-letter-exchange': 'dlx',
        'x-message-ttl': 60000,  # 60秒後進入死信
    }
)

口訣:「傳持認重」(傳輸保證、持久化、確認機制、重試)


Q5:XMPP 的 Presence 有什麼用途?

答案:

Presence(線上狀態) 讓使用者知道對方是否在線,就像 LINE 的「在線中」功能。

狀態類型:

<!-- 在線 -->
<presence/>

<!-- 離開 -->
<presence>
  <show>away</show>
  <status>開會中</status>
</presence>

<!-- 忙碌 -->
<presence>
  <show>dnd</show>  <!-- Do Not Disturb -->
  <status>專注工作中</status>
</presence>

<!-- 離線 -->
<presence type="unavailable"/>

Python 實作:

class MyBot(slixmpp.ClientXMPP):
    async def start(self, event):
        # 設定狀態
        self.send_presence(pshow='away', pstatus='開會中')

        # 監聽好友狀態
        roster = await self.get_roster()
        for jid in roster:
            print(f"{jid}: {roster[jid]['presence']}")

應用場景:

  • 💬 聊天 App:顯示好友在線狀態
  • 🎮 遊戲:顯示玩家在線/遊戲中
  • 💼 協作工具:團隊成員狀態
  • 📞 視訊會議:誰可以接聽

📝 總結

即時通訊協定就像不同的運輸工具:

  • MQTT:機車 🏍️(輕巧靈活,適合短途)
  • XMPP:汽車 🚗(舒適全面,適合日常)
  • STOMP:腳踏車 🚲(簡單易用,適合新手)
  • AMQP:卡車 🚚(可靠穩重,適合貨運)

根據你的需求選擇適合的協定,沒有最好的協定,只有最適合的!

記憶口訣:

  • 「物聯 MQTT,聊天 XMPP,網頁 STOMP,企業 AMQP」

🔗 延伸閱讀

0%