為shell佈置陷阱:trap捕捉信號方法論

来源:http://www.cnblogs.com/f-ck-need-u/archive/2017/08/30/7454174.html
-Advertisement-
Play Games

本文目錄: 1.1 信號說明 1.2 trap佈置陷阱 1.3 佈置完美陷阱必備知識 家裡有老鼠,快消滅它!哎,又給跑了。老鼠這小東西跑那麼快,想直接直接消滅它還真不那麼容易。於是,老鼠藥、老鼠夾子或老鼠籠就派上用場了,它們都是陷阱,放在那靜靜地等待著老鼠的光顧。 在shell中,也可以捉"老鼠", ...



本文目錄:

1.1 信號說明

1.2 trap佈置陷阱

1.3 佈置完美陷阱必備知識


家裡有老鼠,快消滅它!哎,又給跑了。老鼠這小東西跑那麼快,想直接直接消滅它還真不那麼容易。於是,老鼠藥、老鼠夾子或老鼠籠就派上用場了,它們都是陷阱,放在那靜靜地等待著老鼠的光顧。

在shell中,也可以捉"老鼠",捉到"老鼠"後,可以無視它、殺死它或者抓起來逗一番。只需使用內置命令trap(中文就翻譯為陷阱、圈套)就可以佈置一個陷阱,這個陷阱當然不是捕老鼠的,而是捕捉信號。

通常trap都在腳本中使用,主要有2種功能:

(1).忽略信號。當運行中的腳本進程接收到某信號時(例如誤按了CTRL+C),可以將其忽略,免得腳本執行到一半就被終止。

(2).捕捉到信號後做相應處理。主要是清理一些腳本創建的臨時文件,然後退出。

1.1 信號說明

詳細的信號說明見:信號。常見的信號以及它們的數值代號、說明如下:

Signal     Value     Comment
─────────────────────────────
SIGHUP        1      終止進程,特別是終端退出時,此終端內的進程都將被終止
SIGINT        2      中斷進程,幾乎等同於sigterm,會儘可能的釋放執行clean-up,釋放資源,保存狀態等(CTRL+C)
SIGQUIT       3      從鍵盤發出殺死(終止)進程的信號
 
SIGKILL       9      強制殺死進程,該信號不可被捕捉和忽略,進程收到該信號後不會執行任何clean-up行為,所以資源不會釋放,狀態不會保存
SIGTERM      15      殺死(終止)進程,幾乎等同於sigint信號,會儘可能的釋放執行clean-up,釋放資源,保存狀態等
 
SIGSTOP      19      該信號是不可被捕捉和忽略的進程停止信息,收到信號後會進入stopped狀態
SIGTSTP      20      該信號是可被忽略的進程停止信號(CTRL+Z)

每個信號其真實名稱並非是SIGXXX,而是去除SIG後的單詞,每個信號還有其對應的數值代號,在使用信號時,可以使用這3種方式中的任一一種。例如SIGHUP,它的信號名稱為HUP,數值代號為1,發送HUP信號時,以下3種方式均可。

kill -1 PID
kill -HUP PID
kill -SIGHUP PID

在上面所列的信號列表中,KILL和STOP這兩個信號無法被捕捉。一般來說,在設置信號陷阱時,只會考慮HUP、INT、QUIT、TERM這4個會終止、中斷進程的信號。

1.2 trap佈置陷阱

trap的語法格式為:

1.   trap [-lp]
2.   trap cmd-body signal_list
3.   trap '' signal_list
4.   trap    signal_list
5.   trap -  signale_list
 
語法說明:
語法1:-l選項用於列出當前系統支持的信號列表,和"kill -l"一樣的作用。
       -p選項用於列出當前shell環境下已經佈置好的陷阱。
語法2:當捕捉到給定的信號列表中的某個信號時,就執行此處給定cmd-body中的命令。
語法3:命令參數為空字元串,這時shell進程和shell進程內的子進程都會忽略信號列表中的信號。
語法4:省略命令參數,重置陷阱為啟動shell時的陷阱。不建議此語法,當給定多個信號時結果會出人意料。
語法5:等價於語法4。
trap不接任何參數和選項時,預設為"-p"

(1).查看當前shell已佈置的陷阱。

[root@xuexi ~]# trap
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU

這3個陷阱都是信號忽略陷阱,當捕獲到TSTP、TTIN或TTOU信號時,將不做任何處理。

(2).設置一個可以忽略CTRL+C和15信號的陷阱。

[root@xuexi ~]# trap '' SIGINT SIGTERM
[root@xuexi ~]# trap
trap -- '' SIGINT
trap -- '' SIGTERM
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU

這樣一來,當前的shell就無法被kill -15殺死。

[root@xuexi ~]# kill $BASHPID;echo kill current bash failed
kill current bash failed

(3).設置一個陷阱,當這個陷阱捕捉到15信號時,就列印一條消息。

[root@xuexi ~]# trap 'echo caught the TERM signal' TERM 
[root@xuexi ~]# kill $BASHPID
caught the TERM signal

再查看已設置的陷阱,之前設置為忽略TERM信號的陷阱已經被覆蓋。

[root@xuexi ~]# trap
trap -- '' SIGINT
trap -- 'echo caught the TERM signal' SIGTERM
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU

(4).重置針對INT和TERM這兩個信號的陷阱為初始狀態。

[root@xuexi ~]# trap - SIGINT SIGTERM
[root@xuexi ~]# trap
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU

(5).在腳本中設置一個能忽略CTRL+C和SIGTERM信號的陷阱。

[root@xuexi ~]# cat trap1.sh
#!/bin/bash
# script_name: trap1.sh
#
trap '' SIGINT SIGTERM
sleep 10
echo sleep success

當執行該腳本後,將首先陷入睡眠狀態,按下CTRL+C將無效。仍會執行完所有的命令。

[root@xuexi ~]# ./trap1.sh
^C^C^C^Csleep success

(6).佈置一個當腳本中斷時能清理垃圾並退出立即腳本的陷阱。

[root@xuexi ~]# cat trap1.sh
#!/bin/bash
# script_name: trap1.sh
#
trap 'echo trap handling...;rm -rf /tmp/$BASHPID$BASHPID;echo TEMP file cleaned;exit' SIGINT SIGTERM SIGQUIT SIGHUP
mkdir -p /tmp/$BASHPID$BASHPID/
touch /tmp/$BASHPID$BASHPID/{a.txt,a.log}
sleep 10
echo first sleep success
sleep 10
echo second sleep success

這樣,無論是什麼情況中斷(除非是SIGKILL),腳本總能清理掉臨時垃圾。

1.3 佈置完美陷阱必備知識

(1).陷阱的守護對象是shell進程本身,不會守護shell環境內的子進程。但如果是信號忽略型陷阱,則會守護整個shell進程組使其忽略給定信號。

以下麵這個腳本為例,設置的陷阱會捕捉到SIGING和SIGTERM兩個信號,捕捉到信號時將輸出陷阱做出處理的時間點。

[root@xuexi ~]# cat trap2.sh
#!/bin/bash
# script_name: trap2.sh
#
trap 'echo trap_handle_time: $(date +"%F %T")' SIGINT SIGTERM
echo time_start: $(date +"%F %T")
sleep 10
echo time_end1: $(date +"%F %T")
sleep 10
echo time_end2: $(date +"%F %T")

執行該腳本,並另開一個會話視窗,殺死trap2.sh腳本。

[root@xuexi ~]# ./trap2.sh
[root@xuexi ~]# killall -s SIGTERM trap2.sh

執行結果如下。

time_start: 2017-08-14 12:59:23
trap_handle_time: 2017-08-14 12:59:33  
time_end1: 2017-08-14 12:59:33
time_end2: 2017-08-14 12:59:43

結果中的trap_handle_time證明,腳本所在shell進程收到SIGTERM信號後,trap成功進行了處理。如果細心的話,會發現trap處理的時間正好是10秒之後,這並不是因為正好10秒之後才發送SIGTERM信號,而是因為trap就是這麼工作的,這是另一個需要註意的點,稍後見下文的(2)。

再次執行腳本,在另個會話視窗下殺死腳本中正在運行的sleep進程和trap2.sh腳本所在進程。

[root@xuexi ~]# ./trap2.sh
[root@xuexi ~]# killall -s SIGTERM sleep ;sleep 3; killall -s SIGINT trap2.sh  # 另一個會話終端下執行此命令

最終將返回如下結果:

time_start: 2017-08-14 12:23:06
Terminated                        # 接收到對sleep發送的SIGTERM信號
time_end1: 2017-08-14 12:23:09    # 沒有trap_handle_time,陷阱沒有守護sleep進程
trap_handle_time: 2017-08-14 12:23:19   # shell進程本身收到了SIGINT信號,並被陷阱處理了
time_end2: 2017-08-14 12:23:19

結果說明腳本中的trap陷阱沒有守護shell內的sleep進程,只守護了shell本身。同樣也發現了,雖然是在3秒後發送INT信號給腳本進程,但陷阱同樣是在10秒之後才開始處理的。

再修改腳本中的陷阱為信號忽略陷阱。

[root@xuexi ~]# cat ./trap3.sh
#!/bin/bash
# script_name: trap3.sh
#
trap '' SIGINT SIGTERM
echo time_start: $(date +"%F %T")
sleep 10
echo time_end1: $(date +"%F %T")
sleep 10
echo time_end2: $(date +"%F %T")

執行trap3.sh,併在另一個會話終端下殺死sleep進程。

[root@xuexi ~]# ./trap3.sh
[root@xuexi ~]# killall -s SIGTERM sleep;sleep 3;killall -s SIGINT sleep   # 另一個會話終端下執行此命令

結果如下。從時間差可以看出,無論是SIGTERM還是SIGINT信號,sleep進程都被忽略型trap守護了。

time_start: 2017-08-14 12:31:54
time_end1: 2017-08-14 12:32:04
time_end2: 2017-08-14 12:32:14

(2).如果shell中針對某信號設置了陷阱,則該shell進程接收到該信號時,會等待其內正在運行的命令結束才開始處理陷阱。

其實(1)中的幾個示例的結果已經證明瞭這一點。只要是向shell進程發送的信號,都會等待當前正在運行的命令結束後才處理信號,然後繼續腳本向下運行。

(3).CTRL+C和SIGINT不是等價的。當某一時刻按下CTRL+C,它是在向整個當前運行的進程組發送SIGINT信號。對shell腳本來說,SIGINT不僅發送給shell腳本進程,還發送給腳本中當前正在運行的進程。

所以,如果shell中設置SIGINT陷阱,不僅會終止腳本中當前正在運行的進程,trap還會立即進行對應的處理。

以下麵的腳本trap4.sh為例。

[root@xuexi ~]# cat trap4.sh
#!/bin/bash
# script_name: trap4.sh
#
trap 'echo trap_handle_time: $(date +"%F %T")' SIGINT
echo time_start: $(date +"%F %T")
sleep 10
echo time_end1: $(date +"%F %T")
sleep 10
echo time_end2: $(date +"%F %T")

如果使用kill命令向trap4.sh發送信號,正常情況下trap會在當前運行的sleep進程完成後才進行相關處理。但如果是按下CTRL+C,先看結果。

[root@xuexi ~]# ./trap4.sh
time_start: 2017-08-14 13:41:30
^Ctrap_handle_time: 2017-08-14 13:41:31
time_end1: 2017-08-14 13:41:31
^Ctrap_handle_time: 2017-08-14 13:41:32
time_end2: 2017-08-14 13:41:32

結果中顯示,兩次按下CTRL+C後,不僅sleep立刻結束了,trap也立即進行處理了。這說明CTRL+C不僅讓腳本進程收到了SIGINT信號,也讓當前正在運行的進程收到了SIGINT信號。

需要特別說明的是,如果當前正在運行的進程處在迴圈內,當該進程收到了終止進程後,僅僅只是立即終止當次進程,而不會終止整個迴圈,也就是說,它還會繼續向下執行後續命令併進入下一個迴圈。如果此時是使用CTRL+C發送SIGINT,則每次CTRL+C時,trap也會一次次進行處理。

註意點(1)(2)(3)很重要,因為搞清楚了它們,才能明白腳本中當前正在運行的進程是先完成還是立即結束,這在寫複雜腳本或任務型腳本極其重要。例如大量文檔中www.example.com需要替換成www.example.net,假如使用sed進行處理,我們肯定不希望替換了一部分文件的時候被臨時終止。

(4).每個陷阱都有守護範圍。每一個陷阱只將守護它後面的所有進程,直到遇到下一個相同信號的陷阱。

以shell腳本為例,如下圖所示。

(5).當shell環境下設置了信號忽略陷阱時,子shell在啟動時將繼承該陷阱,且這些信號忽略陷阱不可再改變或重置。信號忽略陷阱是子shell唯一繼承的陷阱類型。

先在當前shell環境下設置一個忽略SIGINT的陷阱,和一個不忽略SIGTERM的陷阱。

[root@xuexi ~]# trap '' SIGINT
[root@xuexi ~]# trap 'echo haha' SIGTERM

以下是測試腳本。腳本中首先輸出腳本剛啟動時的最初陷阱列表,隨後修改陷阱並輸出新的陷阱列表,最後重置陷阱並輸出重置後的陷阱列表。

[root@xuexi ~]# cat trap6.sh
#!/bin/bash
# script_name: trap6.sh
echo old_trap:--------
trap -p
trap 'echo haha' SIGINT SIGTERM
echo new_trap:--------
trap -p
echo "reset trap:------"
trap - SIGINT SIGTERM
trap -p

執行結果如下。

[root@xuexi ~]# ./trap6.sh    
old_trap:--------
trap -- '' SIGINT
new_trap:--------
trap -- '' SIGINT
trap -- 'echo haha' SIGTERM
reset trap:------
trap -- '' SIGINT

從結果中可以看出,啟動腳本時,父shell中忽略SIGINT的陷阱被繼承了,但不忽略信號的陷阱未被繼承。而且腳本繼承的信號忽略陷阱無法被修改和重置。

(6).互動式的shell下,如果沒有定義任何SIGTERM信號的陷阱,則會忽略該信號。

所以,在預設(未定義SIGTERM陷阱)時,無法直接通過15信號殺死當前bash進程。

[root@xuexi ~]# kill $BASHPID;echo passed;kill -9 $BASHPID
passed
           # 此處當前bash已被kill -9強制殺死

(7).除了kill -l或trap -l列出的信號列表,trap還有4種特殊的信號:EXIT(或信號代碼0)、ERR、DEBUG和RETURN。DEBUG和RETURN這兩種信號陷阱無需關註。

EXIT信號也是0信號,當設置了EXIT陷阱時,每次exit的時候都會被捕捉,並做相關處理。

ERR陷阱是在設置了"set -e"時生效的,當設置了"set -e"選項,每次遇到非0退出狀態碼時會退出當前shell,如果寫在腳本中,就是退出腳本。有了它就不用再在腳本中書寫對"$?"是否(不)等於0的判斷語句,不過它主要用於避免腳本中產生錯誤時,錯誤被滾雪球式的不斷放大。很多人將這一設置當作寫shell腳本的一項行為規範,但我個人不完全認同,很多時候非0退出狀態碼是無關緊要的,甚至有時候非0狀態碼才是繼續執行的必要條件。

回到話題上。先看看"set -e"的效果。以下麵的腳本為例,在腳本中,mv命令少給了一個參數,它是錯誤命令,返回的是非0狀態碼。

[root@xuexi ~]# vim trap8.sh
#!/bin/bash
set -e
echo "right here"
mv ~/a.txt
[ "$?" -eq 0 ] && echo "right again" || echo "wrong here"

如果不設置"set -e",那麼會被下一條語句判斷,但因為設置了"set -e",使得在mv錯誤發生時,就立即退出腳本所在的shell。也就是說,對"$?"的判斷語句根本就是多餘的。結果如下。

[root@xuexi ~]# ./trap8.sh
right here
mv: missing destination file operand after ‘/root/a.txt’
Try 'mv --help' for more information.

可以設置ERR陷阱,專門捕獲"set -e"起作用時的信號。例如,當命令錯誤時,做一些臨時文件清理動作等。註意,當捕獲到了ERR信號時,腳本不會再繼續向下運行,而是trap處理結束後就立即退出。例如:

[root@xuexi ~]# vim trap8.sh
#!/bin/bash
set -e
trap 'echo continue' ERR
echo "right here"
mv ~/a.txt
[ "$?" -eq 0 ] && echo "right again" || echo "wrong here"
echo haha

執行結果如下:

[root@xuexi ~]# ./trap8.sh 
right here
mv: missing destination file operand after ‘/root/a.txt’
Try 'mv --help' for more information.
continue

(8).在trap中兩個很好用的變數:BASH_COMMAND和LINENO。BASH_COMMAND變數記錄的是當前正在執行的命令行,如果是用在陷阱中,則記錄的是陷阱觸發時正在運行的命令行。LINENO記錄的是正在執行的命令所處行號。

例如:

[root@xuexi ~]# vim trap8.sh
#!/bin/bash
set -e
trap 'echo "error line: $LINENO,error cmd: $BASH_COMMAND"' ERR
echo "right here"
mv ~/a.txt

執行結果。

[root@xuexi ~]# ./trap8.sh  
right here
mv: missing destination file operand after ‘/root/a.txt’
Try 'mv --help' for more information.
error line: 5,error cmd: mv ~/a.txt

(9).處理腳本中啟動的後臺進程。

通常trap在腳本中的作用之一是在突然被中斷時清理一些臨時文件然後退出,雖然它會等待腳本中當前正在運行的命令結束,然後清理並退出。但是,很多時候會在腳本中使用後臺進程,以加快腳本的速度。而後臺進程是獨立掛靠在init/systemd下的,所以它不受終端以及shell環境的影響。換句話說,當腳本突然被中斷時,即使陷阱捕獲到了該信號,並清理了臨時文件後退出,但是那些腳本中啟動的後臺進程還會繼續運行。

這就給腳本帶來了一些不可預測性,一個健壯的腳本必須能夠正確處理這種情況。trap可以實現比較好的解決這種問題,方法是在trap的命令行中加上向後臺進程發送信號的語句,然後再退出。

以下麵的腳本為例。

[root@xuexi ~]# vim trap10.sh
#!/bin/bash
trap 'echo first trap $(date +"%F %T");exit' SIGTERM
echo first sleep $(date +"%F %T")
sleep 20 &
echo second sleep $(date +"%F %T")
sleep 5

該腳本中首先將一個sleep放入後臺運行。正常情況下,該腳本執行5秒後就會退出,但在20秒後後臺進程sleep才會結束,即使突然發送中斷信號TERM觸發trap也一樣。

於是現在的目標是,在sleep 5的過程中突然中斷腳本時,能殺死後臺sleep進程。可以使用"!"這個特殊變數。修改後的腳本如下。

[root@xuexi ~]# vim trap10.sh
#!/bin/bash
trap 'echo first trap $(date +"%F %T");kill $pid;exit' SIGTERM
echo first sleep $(date +"%F %T")
sleep 20 &
pid="$!"
sleep 30 &
pid="$! $pid"
echo second sleep $(date +"%F %T")
sleep 5

執行該腳本,併在另一個會話視窗發送SIGTERM信號給該腳本進程。

[root@xuexi ~]# ./trap10.sh ; ps aux | grep sleep       
[root@xuexi ~]# kill trap10.sh    # 另一個會話視窗執行

執行結果如下。可見sleep被正常終止。

first sleep 2017-08-14 21:29:19
second sleep 2017-08-14 21:29:19
first trap 2017-08-14 21:29:24
root      69096  0.0  0.0 112644   952 pts/0    S+   21:29   0:00 grep --color=auto sleep

 

回到系列文章大綱:http://www.cnblogs.com/f-ck-need-u/p/7048359.html

轉載請註明出處:http://www.cnblogs.com/f-ck-need-u/p/7454174.html

註:若您覺得這篇文章還不錯請點擊下右下角的推薦,有了您的支持才能激發作者更大的寫作熱情,非常感謝!


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

-Advertisement-
Play Games
更多相關文章
  • 背景 最近越來越多的公司把業務搬遷到雲上,公司也有這個計劃,自己抽時間在阿裡雲和Azure上做了一些小的嘗試,現在把阿裡雲上部署ES和kibana記錄下來。為以後做一個參考,也希望對其他人有幫助。 這裡以阿裡雲為例,由於測試只有一臺機器所以這裡就展開到集群了,下麵介紹下詳細的步驟。 步驟: 1.申請 ...
  • 第一次在博客園寫博客,也算是一個新的開始吧。閑話少說! 筆者之前推行OA系統的時候,管理員賬號一開始設的是admin,用了一段時間之後為了規範統一要改為ADMIN。 那問題來了,除了用戶表之外,還有哪些表哪些欄位的內容,已經記錄了admin呢? 上網查了表及欄位的相關知識之後,加上游標整庫搜索,終於 ...
  • SQL Server 使用兩個內部數據結構跟蹤被大容量複製操作修改的區,以及自上次完整備份後修改的區。這些數據結構極大地加快了差異備份的速度。當資料庫使用大容量日誌恢復模式時,這些數據結構也可以加快將大容量複製操作記錄至日誌的速度。與全局分配圖 (GAM) 和共用全局分配圖 (SGAM) 頁相同,這 ...
  • 摘要: 作為對垃圾游戲時代的致敬, Andreas Streichhardt 使用ArangoDB 資料庫創建了一個Flash 游戲來紀念這個時代。快來看看吧! ...
  • 版本: 主機:Windows 7 64位旗艦版 VMWare 10 + Windows 7 64位旗艦版 VMWare 10 + Ubuntu16.04LTS 64位 文件夾共用【Windows】: 註:先安裝VMWare Tools(如下拖拽(複製粘貼)【Windows】) 1)虛擬機採用橋接的網 ...
  • 好煩,又要寫摘要,主要是自己不會說些違心的話,又不願意發惱騷,但還是記錄一下自己目前的狀態和心情吧。生活內容很豐富但實際很平淡,除了親人帶給我一些驚喜外,我嗅不到任何新鮮了。我不知道自己價值多大,被認可的價值有多大,但我不能發惱騷,畢竟我是一個有內涵的程式猿。於是我想,是我不夠全面不夠自信不夠勇敢吧 ...
  • 本文目錄: 1.1 dd命令 1.2 split命令 1.3 csplit命令 在Linux最常用的文件生成和切片工具是dd,它功能比較全面,但無法以行為單位提取文件數據,也無法直接將文件按大小或行數進行均分(除非藉助迴圈)。另兩款數據分割工具split和csplit能夠比較輕鬆地實現這些需求。cs ...
  • uniq是去重,不相鄰的行不算重覆值。 uniq [OPTION]... [INPUT [OUTPUT]] 選項說明: -c:統計出現的次數(count)。 -d:只顯示被計算為重覆的行。 -D:顯示所有被計算為重覆的行。 -u:顯示唯一值,即沒有重覆值的行。 -i:忽略大小寫。 -z:在末尾使用\ ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...