Python 客戶端類庫之paho-mqtt學習總結

来源:https://www.cnblogs.com/shouke/p/18417803
-Advertisement-
Play Games

實踐環境 Python 3.9.13 paho-mqtt 2.1.0 簡介 Eclipse Paho MQTT Python客戶端類庫實現了MQTT 協議版本 5.0, 3.1.1, 和3.1。 該類庫提供一個客戶端類,允許應用連接到MQTT代理併發布消息,訂閱主題並檢索發佈的消息。同時還提供了一個 ...


實踐環境

Python 3.9.13

paho-mqtt 2.1.0

簡介

Eclipse Paho MQTT Python客戶端類庫實現了MQTT 協議版本 5.0, 3.1.1, 和3.1。

該類庫提供一個客戶端類,允許應用連接到MQTT代理併發布消息,訂閱主題並檢索發佈的消息。同時還提供了一個寫其它輔助函數,使向MQTT伺服器發佈一次性消息變得非常簡單。

支持 Python 3.7+。

MQTT協議是一種機器對機器(M2M)/“物聯網”連接協議。它被設計為一種極其輕量級的發佈/訂閱消息傳輸,對於需要小代碼占用和/或網路帶寬非常昂貴的遠程連接非常有用。

安裝

pip install paho-mqtt

已知限制

以下是已知的未實現的MQTT功能。

clean_sessionFalse時,會話僅存儲在記憶體中,不會持久化。這意味著當客戶端重新啟動時(不僅僅是重新連接,通常是因為程式重新啟動而重新創建對象),會話就會丟失。這可能會導致消息丟失。

客戶端會話的以下部分丟失:

  • 已從伺服器接收到但尚未完全確認的 QoS 2 消息。

    由於客戶端會盲目確認任何PUBCOMP(QoS 2 事務的最後一條消息),因此它不會掛起,但會丟失此 QoS 2 消息。

  • 已發送到伺服器但尚未完全確認的 QoS 1 和 QoS 2 消息。

    這意味著傳遞給 publish()的消息可能會丟失。這可以通過讓傳遞給 publish() 的所有消息都有相應的on_publish() 調用或使用wait_for_publish來緩解。

    這也意味著代理在會話中可能有 QoS2 消息。由於客戶端從一個空會話開始,它不知道它,並將重用mid。這還沒有解決。

此外,當clean_sessionTrue時,此類庫將在網路重新連接時重新發佈 QoS > 0消息。這意味著 QoS > 0消息不會丟失。但標準規定,我們應該丟棄發送發佈包的任何消息。設置為True意味著不符合標準,QoS 2 可能會被接收兩次。

如果只需要一次交付的 QoS 2 保證,則應設置clean_session=False

用法與API

API詳細線上文檔:https://eclipse.dev/paho/files/paho.mqtt.python/html/client.html

示例:https://github.com/eclipse/paho.mqtt.python/tree/master/examples

開始

下麵是一個非常簡單的示例,它訂閱代理$SYS主題樹並列印出結果消息:

# -*- coding:utf-8 -*-

import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, reason_code, properties):
    '''客戶端從伺服器接收到 CONNACK 響應時的回調'''

    print(f"Connected with result code {reason_code}")  # 成功連接時 reason_code 值為 Success

    # 在on_connect()中執行訂閱操作,意味著如果應用失去連接並且重新連接後,訂閱將被續訂。
    if reason_code == 'Success':
        client.subscribe('$SYS/#')

def on_disconnect(client, userdata, flags, reason_code, properties):
    print(f'Disconnected with result code {reason_code}')


def on_message(client, userdata, msg):
    '''從伺服器收到 PUBLISH 消息時的回調。'''
    print(msg.topic + ' ' + str(msg.payload)) # 輸出值形如 $SYS/broker/version b'mosquitto version 2.0.18'

mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.on_connect = on_connect
mqttc.on_disconnect = on_disconnect
mqttc.on_message = on_message
 
# client.username_pw_set('testacc', 'test1234') # 設置訪問賬號和密碼

mqttc.connect("mqtt.eclipseprojects.io", 1883, 60)

# 阻塞調用,處理網路流量、分派回調和處理重新連接
# 有其它提供線程介面和手動介面的loop*()函數可用
mqttc.loop_forever()

說明:

  1. Client.username_pw_set(username: str | None, password: str | None = None*) → None

    為代理身份驗證設置用戶名和密碼(可選)。

    必須在connect()之前調用才能生效。需要支持MQTT v3.1或更高版本的代理。

    • 參數:
      • username – 要進行身份驗證的用戶名。需要與客戶端id沒有關係。必須是字元串[MQTT-3.1.3-11]。設置為“None”可將客戶端重置為不使用用戶名/密碼進行代理身份驗證。
      • password – 用於身份驗證的密碼。可選,如果不需要,則設置為None。如果為字元串r,那麼它將被編碼為UTF-8。
  2. Client.connect(host: str, port: int = 1883, keepalive: int = 60, bind_address: str = '', bind_port: int = 0, clean_start: bool | Literal[3] = 3, properties: Properties|None = None) → MQTTErrorCode
    

    連接到遠程代理。這是一個阻塞調用,用於建立底層連接並傳輸CONNECT數據包。請註意,在收到並處理CONNACK之前,連接狀態不會更新(這需要一個正在運行的網路迴圈,請參閱loop_start, loop_forever, loop…)).
    參數

    • host– 遠程代理的主機名或IP地址。

    • port– 要連接的伺服器主機的網路埠。預設為1883。請註意,SSL/TLS上MQTT的預設埠是8883,因此如果使用TLS_set()可能需要提供埠。

    • keepalive - 設置心跳的時間,單位是秒。這個值告訴MQTT客戶端,在沒有接收到任何通信的情況下,多久應該發送一個PING請求給伺服器,以保持連接,預設60秒。

    • clean_start -(僅限MQTT v5.0)TrueFalseMQTT_CLEAN_START_FIRST_ONLY。總是設置MQTT v5.0 clean_start標誌、從不或僅在第一次成功連接時。設置clean_start標誌後,MQTT會話數據(如未完成的消息和訂閱)在成功連接時被清除。對於MQTT v3.1.1,Clientclean_session參數應用於類似的結果。

    • properties (Properties) –( 僅僅限MQTT v5.0)需要在MQTT連接包發送的的MQTT v5.0 屬性。

客戶端(Client)

Client類一般使用流程如下:

  1. 創建客戶端實例
  2. 使用connect*() 函數之一連接到代理
  3. 調用其中一個loop*()函數來維護代理的網路流量
  4. 使用subscribe()訂閱主題並接收消息
  5. 使用publish()將消息發佈到代理
  6. 使用disconnect()斷開與代理的連接

將調用回調以允許應用程式根據需要處理事件。這些回調如下所述。

網路迴圈

這些功能是Client背後的驅動力。如果它們沒有被調用,傳入的網路數據將不會被處理,傳出的網路數據也不會被髮送。管理網路環路有四種選擇。這裡描述了三個,第四個在下麵的“外部事件迴圈支持”中描述。不要混合使用不同的loop函數。

loop_start() / loop_stop()
mqttc.loop_start()

while True:
    temperature = sensor.blocking_read()
    mqttc.publish("paho/temperature", temperature)

mqttc.loop_stop()

這些函數實現了網路迴圈的線程介面。在connect*()之前或之後調用loop_start()一次,會在後臺運行一個線程來自動調用loop()。這釋放了主線程,用於可能阻塞的其他工作。此調用還處理與代理的重新連接。調用loop_stop() 以停止後臺線程。如果調用disconnect(),迴圈也會停止。

loop_forever()
mqttc.loop_forever(retry_first_connection=False)

這是網路迴圈的阻塞形式,在客戶端調用disconnect()之前不會返回(即調用mqttc.disconnect()後會停止阻塞,繼續運行其後的代碼)。它會自動處理重新連接。
除了使用connect_async時的第一次連接嘗試外,使用retry_first_connection=True 使其重試第一次連接。
警告:這可能會導致客戶端保持連接到不存在的主機而不會出現失敗。

loop()
run = True
while run:
    rc = mqttc.loop(timeout=1.0)
    if rc != 0:
        # need to handle error, possible reconnecting or stopping the application

定期調用以處理網路事件。此調用觸發select()等待,直到網路套接字可用於讀取或寫入,如果套接字可用,則處理流入/流出的數據。此函數最多阻塞timeout秒。timeout不能超過客戶端的keepalive值,否則代理會定期斷開客戶端的連接。
使用這種迴圈,需要自己處理重新連接策略。

回調

與paho-mqtt交互的介面包括各種回調,當發生某些事件時,類庫會調用這些回調。

回調是在代碼中定義的函數,用於實現對這些事件要求的操作。這可能只是列印收到的消息,也可能是更複雜的行為。

回調API是有版本的,所選版本是我們提供給客戶端構造函數的CallbackAPIVersion。目前支持兩個版本:

  • CallbackAPIVersion.VERSION1:這是paho-mqtt 2.0版本之前使用的歷史版本。它是在引入CallbackAPIVersion之前使用的API。此版本已棄用,將在paho-mqtt 3.0版本中刪除。
  • CallbackAPIVersion.VERSION2:此版本在協議MQTT 3.x和MQTT 5.x之間更為一致。它也更適用於MQTT 5.x,因為reason_code和屬性始終在可獲取時提供。建議所有用戶升級到此版本。強烈建議MQTT 5.x用戶使用。

存在以下回調:

  • on_connec():當收到代理返回CONNACK時被調用。調用可能是針對被拒絕的連接,請檢查reason_code以查看連接是成功還是被拒絕。
  • on_connect_fail():當TCP連接建立失敗時,由loop_forever()loop_start()調用。當直接使用connect()reconnect()時,不會調用此回調。它僅由loop_start()loop_forever()製造的自動(重新)連接後被調用
  • on_disconnect():當連接關閉時被調用。
  • on_message():收到代理返回的MQTT消息時被調用。
  • on_publish():當MQTT消息發送到代理時被調用。取決於QoS級別,回調在不同時刻被調用:
    • 對於QoS==0,一旦消息通過網路發送,就會調用它。這可能是在相應的publish()返回之前。
    • 對於QoS==1,當收到代理返回的對應消息的PUBACK時調用它
    • 對於QoS==2,當收到代理返回的對應消息的PUBCOMP時,會調用它
  • on_subscribe():當收到代理返回的SUBACK時被調用
  • on_unsubscribe:當收到代理返回的UNSUBACK時被調用
  • on_log():當類庫記錄一條消息時被調用
  • onSocket_openonSocket_closeonSocket_register_writeonSocket_unregister_write:用於外部迴圈支持(External event loop support)的回調。詳見下文。

參閱線上文檔查看有關每個回調的特征。

訂閱示例
# -*- coding:utf-8 -*-

import paho.mqtt.client as mqtt

def on_subscribe(client, userdata, mid, reason_code_list, properties):
    # 由於我們只訂閱了一個通道,reason_code_list只包含一個條目
    # print(reason_code_list) #輸出: [ReasonCode(Suback, 'Granted QoS 0')]
    if reason_code_list[0].is_failure:
        print(f"Broker rejected you subscription: {reason_code_list[0]}")
    else:
        print(f"Broker granted the following QoS: {reason_code_list[0].value}")

def on_unsubscribe(client, userdata, mid, reason_code_list, properties):
    #註意,reason_code_list僅存在於MQTTv5中,在MQTTv3中,它將始終為空
    if len(reason_code_list) == 0 or not reason_code_list[0].is_failure:
        print("unsubscribe succeeded (if SUBACK is received in MQTTv3 it success)")
    else:
        print(f"Broker replied with failure: {reason_code_list[0]}")
    client.disconnect()

def on_message(client, userdata, message):
    # userdata是我們選擇提供的數據結構,這裡為一個列表(通過下方的 mqttc.user_data_set([])設置,該函數參數即為userdata參數值
    userdata.append(message.payload)
    # 假設只想處理10條消息
    if len(userdata) >= 10:
        client.unsubscribe("$SYS/#")

def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Failed to connect: {reason_code}. loop_forever() will retry connection")
    else:
        # 應該始終在 on_connect 回調中訂閱以確保在重新連接時訂閱依舊存在。
        client.subscribe("$SYS/#")

mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.on_connect = on_connect
mqttc.on_message = on_message
mqttc.on_subscribe = on_subscribe
mqttc.on_unsubscribe = on_unsubscribe

mqttc.user_data_set([]) # 設置 userdata
mqttc.connect("mqtt.eclipseprojects.io")
mqttc.loop_forever() # 當調用client.disconnect()後繼續執行以下代碼

print(f"Received the following message: {mqttc.user_data_get()}")
發佈示例
# -*- coding:utf-8 -*-

import time
import paho.mqtt.client as mqtt

def on_publish(client, userdata, mid, reason_code, properties):
    '''reason_code和properties將僅出現在MQTTv5中。在MQTTv3中始終未設置
    使用不存在`uncaked_publish`中的`mid`調用`on_publish()`。這是由於不可避免的競爭情形:
    * publish() 返回已發送消息的mid。
    * 主線程將publish()返回的mid添加到uncaked_publish中
    * loop_start線程調用on_publish()
    雖然不太可能(因為on_publish()將在網路往返後調用),但是這是一種可能發生的競爭情形
    避免競爭情形的最佳解決方案是使用publish()中的msg_info。還可以嘗試使用已確認的mid列表,而不是從待處理列表中刪除
    但是請記住,mid可以重覆使用!
    reason_code和properties將僅出現在MQTTv5中。在MQTTv3中始終未設置
    '''
    try:
        userdata.remove(mid)
    except KeyError:
        print("on_publish() is called with a mid not present in unacked_publish")
        print("This is due to an unavoidable race-condition:")
        print("* publish() return the mid of the message sent.")
        print("* mid from publish() is added to unacked_publish by the main thread")
        print("* on_publish() is called by the loop_start thread")
        print("While unlikely (because on_publish() will be called after a network round-trip),")
        print(" this is a race-condition that COULD happen")
        print("")
        print("The best solution to avoid race-condition is using the msg_info from publish()")
        print("We could also try using a list of acknowledged mid rather than removing from pending list,")
        print("but remember that mid could be re-used !")

unacked_publish = set()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.on_publish = on_publish

mqttc.user_data_set(unacked_publish)
mqttc.connect("mqtt.eclipseprojects.io")
mqttc.loop_start()

# 應用生產一些消息
msg_info = mqttc.publish("paho/test/topic", "my message", qos=1)
unacked_publish.add(msg_info.mid)

msg_info2 = mqttc.publish("paho/test/topic", "my message2", qos=1)
unacked_publish.add(msg_info2.mid)

# 等待所有消息被髮布
while len(unacked_publish):
    time.sleep(0.1)

# 由於上述描述的競爭狀態, 以下等待所有消息發佈完成的方式更安全
msg_info.wait_for_publish()
msg_info2.wait_for_publish()

mqttc.disconnect()
mqttc.loop_stop()

說明:

  1. Client.max_inflight_messages_set(inflight: int) → None

    設置一次可以通過其網路流的QoS>0的消息的最大數量(可以簡單理解為允許多大數量的QoS>0的消息被同時進行傳輸處理)。預設值為20。

  2. Client.max_queued_messages_set(queue_size:int)→ Client
    設置傳出消息隊列中的最大消息數量。0表示無限制。

  3. MQTTMessageInfo.wait_for_publish(timeout: float | None = None) → None

    阻塞,直到與此對象關聯的消息被髮布,或者直到超時發生。如果timeoutNone,則永遠不會超時。將超時設置為正數秒,例如1,2,以啟用超時。
    拋出:

    • ValueError–如果消息因傳出隊列已滿而未排隊。
    • RuntimeError-如果消息因其他原因未發佈。
  4. 實踐過程中發現,採用多線程併發發佈消息時,如果伺服器因為限流的原因不返回消息確認,那麼運行一小段時間後,出現消息無法發佈成功的情況(不報錯,但是消息無法抵達broker),通過合理的參數調用以上三個函數,可以緩解這個問題。

Logger

客戶端會發出一些日誌消息,這些消息在故障排除過程中可能很有用。啟用日誌最簡單的方法是調用enable_logger()。可以提供自定義記錄器或使用預設記錄器

示例:

import logging
import paho.mqtt.client as mqtt

logging.basicConfig(level=logging.DEBUG)

mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.enable_logger()

mqttc.connect("mqtt.eclipseprojects.io", 1883, 60)
mqttc.loop_start()

# Do additional action needed, publish, subscribe, ...
[...]

還可以定義一個on_log回調,它將接收所有日誌消息的副本。例子:

import paho.mqtt.client as mqtt

def on_log(client, userdata, paho_log_level, messages):
    if paho_log_level == mqtt.LogLevel.MQTT_LOG_ERR:
        print(message)

mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.on_log = on_log

mqttc.connect("mqtt.eclipseprojects.io", 1883, 60)
mqttc.loop_start()

# Do additional action needed, publish, subscribe, ...
[...]

Paho日誌級別和標準日誌級別的對應關係如下:

Paho logging
MQTT_LOG_ERR logging.ERROR
MQTT_LOG_WARNING logging.WARNING
MQTT_LOG_NOTICE logging.INFO (no direct equivalent)
MQTT_LOG_INFO logging.INFO
MQTT_LOG_DEBUG logging.DEBUG

外部事件迴圈支持

為了支持其他網路迴圈,如asyncio(參見示例),類庫公開了一些方法和回調來支持這些用例。

存在以下迴圈方法:

  • loop_read:應該在套接字可讀取時調用。
  • loop_write:應該在套接字可寫並且類庫需要寫入數據時調用。
  • loop_misc:應每隔幾秒鐘調用一次,以處理消息重試和ping。

用偽代碼表示如下:

while run:
    if need_read:
        mqttc.loop_read()
    if need_write:
        mqttc.loop_write()
    mqttc.loop_misc()

    if not need_read and not need_write:
        # But don't wait more than few seconds, loop_misc() need to be called regularly
        wait_for_change_in_need_read_or_write()
    updated_need_read_and_write()

棘手的部分是實現updated_need_read_and_write並等待條件變更。為了支持這一點,存在以下方法:

  • socket:當TCP連接打開時返回socket對象。此調用對於基於select迴圈特別有用。請參閱examples/loop_select.py

  • want_write():如果有數據等待寫入,則返回True。這接近於上述偽代碼的need_writew,但還是應該檢查套接字是否可寫。

  • 回調函數on_socket_*

    • on_socket_open:在套接字打開時調用。
    • on_socket_open:在套接字打開時調用。
    • on_socket_close:當套接字即將關閉時調用。
    • on_socket_register_write:當客戶端想要在套接字上寫入數據時調用
    • on_socket_unregister_write:當套接字上沒有更多數據要寫入時調用。

    回調對於事件迴圈特別有用,在事件迴圈中,可以註冊或註銷用於讀寫的套接字。請參閱examples/loop_asyncio.py 獲取示例。

回調總是按以下順序調用:

  • on_socket_open

  • 0或者更多次:

    • on_socket_register_write
    • on_socket_unregister_write
  • on_socket_close

全局輔助函數

客戶端模塊還提供了一些全局輔助函數。

topic_matches_sub(sub, topic)可用於檢查主題(topic)是否與訂閱(subscription)匹配。
例如:

主題foo/bar 將與訂閱foo/#+/bar匹配
主題non/matching 將不匹配訂閱non/+/+

發佈

此模塊提供了兩個輔助函數single()multiple(),允許以一次性方式直接發佈消息。換句話說,它們對於有一個/多個消息要發佈到代理,然後斷開連接而不需要其他任何東西的情況非常有用。

提供的兩個函數是single()multiple()

這兩個函數都支持MQTT v5.0,但目前不允許在連接或發送消息時設置任何屬性。

Single

發佈一條消息到代理,然後徹底斷開連接。

例子:

import paho.mqtt.publish as publish

publish.single("paho/test/topic", "payload", hostname="mqtt.eclipseprojects.io")

Multiple

發佈多條消息到代理,然後徹底斷開連接。

例子:

from paho.mqtt.enums import MQTTProtocolVersion
import paho.mqtt.publish as publish

msgs = [{'topic':"paho/test/topic", 'payload':"multiple 1"},
    ("paho/test/topic", "multiple 2", 0, False)]
publish.multiple(msgs, hostname="mqtt.eclipseprojects.io", protocol=MQTTProtocolVersion.MQTTv5)

訂閱

此模塊提供了兩個輔助函數simple()callback(),以允許直接訂閱和處理消息。

這兩個函數都支持MQTT v5.0,但目前不允許在連接或發送消息時設置任何屬性。

Simple

訂閱一組主題並返回收到的消息。這是一個阻塞函數。
例子:

import paho.mqtt.subscribe as subscribe

msg = subscribe.simple("paho/test/topic", hostname="mqtt.eclipseprojects.io")
print("%s %s" % (msg.topic, msg.payload))

使用回調(Callback)

訂閱一組主題,並使用用戶提供的回調處理收到的消息。

例子:

import paho.mqtt.subscribe as subscribe

def on_message_print(client, userdata, message):
    print("%s %s" % (message.topic, message.payload))
    userdata["message_count"] += 1
    if userdata["message_count"] >= 5:
        # it's possible to stop the program by disconnecting
        client.disconnect()

subscribe.callback(on_message_print, "paho/test/topic", hostname="mqtt.eclipseprojects.io", userdata={"message_count": 0})

參考連接

https://github.com/eclipse/paho.mqtt.python

https://eclipse.dev/paho/files/paho.mqtt.python/html/client.html

作者:授客
微信/QQ:1033553122
全國軟體測試QQ交流群:7156436

Git地址:https://gitee.com/ishouke
友情提示:限於時間倉促,文中可能存在錯誤,歡迎指正、評論!
作者五行缺錢,如果覺得文章對您有幫助,請掃描下邊的二維碼打賞作者,金額隨意,您的支持將是我繼續創作的源動力,打賞後如有任何疑問,請聯繫我!!!
           微信打賞                        支付寶打賞                  全國軟體測試交流QQ群  
              


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 大家好,我是 V 哥,粉絲小A面試阿裡,說被問到 Redis 的記憶體淘汰策略的問題,整理這個筆記給他參考,也分享給大家,如果你遇到這個問題,會怎麼回答呢? Redis 的記憶體淘汰策略是指當Redis的記憶體使用量達到設定的上限時,決定哪些數據應該被移除以便為新數據騰出空間的規則。Redis 提供了多種 ...
  • 正文 跟靈分別後,我在椅子上發了很久的呆。可能有五分鐘吧。就這樣感受著微風吹過身體,聽著身邊熙熙攘攘的聲音。 我不知道為什麼要發呆。自然而然就這樣做了。 過了很久,我意識到可能必須要吃飯了,才起身找飯館。 今天情緒不太好。我不知道是不是因為沒睡夠。不過,並沒有從一開始就很糟糕,到晚上才開始。 先是發 ...
  • UGit 是一款為騰訊內部研發環境特點而定製的 Git 客戶端,旨在提高開發效率和團隊協作的流暢性。UGit 支持 macOS 10.11+、Apple Silicon 和 Win64 位系統。 官方地址:https://ugit.qq.com/zh/index.html 主要特性 Ugit 提供便 ...
  • 類型轉換 類型轉換是將一個值從一種類型更改為另一種類型的過程。例如, 可以將String類型的數據“457”轉換為數值型,也可以將任意類型的 數據轉換為String類型。 如果從低精度數據類型向高精度數據類型轉換,則永遠不會溢出, 並且總是成功的;而把高精度數據類型向低精度數據類型轉換時,則會 有信 ...
  • 本文梳理總結了一些 Java 互聯網項目中常見的 Redis 緩存應用場景,例如常見的 String 類型 Key-Value、對時效性要求高的場景、Hash 結構的場景以及對實時性要求高的場景等,全面涵蓋了 Redis 中所有的 5 種基本類型。 ...
  • 在 Python 中,Zope 提供了一種機制來定義和實現介面。Zope 的介面模塊通常用於創建可重用的組件,並確保組件遵循特定的介面規範。 ...
  • Delete、Drop 和 Truncate delete、truncate 僅僅刪除表裡面的數據,drop會把表的結構也刪除 delete 是 DML 語句,操作完成後,可以回滾,truncate 和 drop 是 DDL 語句,刪除之後立即生效,不能回滾 執行效率:drop > truncate ...
  • python基礎 軟體下載 1.python下載安裝 點擊此鏈接進入官網windows下載地址 點擊箭頭處鏈接下載最新版本,進入頁面後下拉 根據你的機器下載對應版本,一般人使用的是X86架構windos系統,下載箭頭所指即可 若是不知道CPU架構,可見查看cpu架構,x86還是arm 下載後根據指引 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...