Net 高級調試之四:Windbg 動態調試

来源:https://www.cnblogs.com/PatrickLiu/archive/2023/11/01/17788840.html
-Advertisement-
Play Games

一:背景 1. 講故事 前些天有位朋友找到我,說他程式中的線程數爆高,讓我幫忙看下怎麼回事,這種線程數爆高的情況找問題相對比較容易,就讓朋友丟一個dump給我,看看便知。 二:為什麼會爆高 1. 查看托管線程 別人說的話不一定是真,得自己拿數據出來說話,可以用 !t 命令觀察一下便知。 0:000> ...


一、簡介
    
今天是《Net 高級調試》的第四篇文章。到今天為止,也有三篇文章了,對 Windbg 也有初步的認識了,當然,一個工具流暢、熟練的使用,對於我們調試 Net 程式是至關重要的。在前幾篇文章的基礎上,我們這篇文章主要介紹一些和使用 Windbg 有關的命令和操作。就我個人而言,第一次接觸這個東西,還是挺難的,以前從來沒有用過 Windbg,用的最多的就是 Visual Studio 的調試功能。不怕大家笑話,如何通過 Windbg 載入一個 exe,我都不知道,更不要談載入 DUMP 文件。我看第一遍視頻的時候,也不知道說了個啥,命令的執行,調試的開始,都感覺是一頭霧水,似懂非懂,自己一實操,總是得不到別人調試那樣的結果,很是鬱悶。怎麼辦呢?沒辦法,要想學會,除了努力那就是堅持。針對視頻,放慢速度,一幀一幀的按著視頻的操作,自己來一遍,速度雖然慢,但是有些操作開始有了感覺了,當整個視頻系列看了一遍,所有操作都操作一遍,終於有些頭緒了。還是那句老話,一遍不行,那就再來一遍,還不行,那就再來一遍,俗話說的好,書讀千遍,其意自現,我這是第三遍。
     如果在沒有說明的情況下,所有代碼的測試環境都是 Net Framewok 4.8,但是,有時候為了查看源碼,可能需要使用 Net Core 的項目,我會在項目章節里進行說明。好了,廢話不多說,開始我們今天的調試工作。
    調試環境我需要進行說明,以防大家不清楚,具體情況我已經羅列出來。
          操作系統:Windows Professional 10
          調試工具:Windbg Preview(可以去Microsoft Store 去下載)
          開發工具:Visual Studio 2022
          Net 版本:Net Framework 4.8
          CoreCLR源碼:源碼下載
二、相關知識
    
1、Windbg 動態調試
          1.1、調試概況
              在任何一種調試中都有兩個組件:調試器本身,調試目標。
              當調試器【Windbg】附加進程【Attach to Process】時,調試器會給 目標程式 註入一個遠程線程並用 int 3 中斷程式,後續和 Net 程式中的 DebuggerRCThread 線程交互執行命令。int 3 指令之所以可以讓進程中斷,主要是來自於 CPU 硬體中斷,當調試器發出了一個 int 3 的中斷請求,CPU會到內核態執行3號常式,也就是執行【中斷向量表】,內核執行中斷的操作。
              Actor------------》調試器(Windbg)《------------》調試目標(Net 程式,C++程式...)
              以上圖例就是一個調試器的作用和所處的地位。

     2、程式的中斷和恢復執行
          2.1、中斷執行(讓程式中斷有4中方式)
              a、使用WinDbg 啟動程式,在進程初始化函數中,如果發現有調試器附加在上面,就會執行 break 中斷。 
                  說明一下:Windbg 調試器剛開始的中斷就是 int 3 中斷,但是這個中斷的時機很早,我們可以做一些初始化的工作,比如:載入SOS.dll 等類似的工作。                
              b、附加進程,調試器會註入遠程線程執行 int 3 中斷程式。
                  這個挺簡單的,我們雙擊程式,直接運行。然後通過 Windbg 的【Attach to process】附加進程,就可以進入調試器界面,這個時候,其實什麼也不用做,調試器已經暫停了,這個暫停就是 int 3 中斷。我們通過 Windbg 的【break】命令也是 int 3 中斷。當然,我們通過 C# Debugger.Break() 代碼執行的也是 int 3 的中斷。
              c、使用 bp 命令給程式下斷點。
                  我們可以通過【u】命令查看方法的彙編代碼,找到想要設斷點的代碼的地址,直接通過這個地址來下斷點,當程式再次運行的時候,就會在這個斷點處暫停。                 
              d、異常中斷。
                   異常中斷的流程是:當你的程式發生異常,會從用戶態轉到內核態,內核態檢測到你的程式附加了調試器,內核態就會把這個請求轉交給調試器,調試器也就能中斷了,可以調試了。
          2.2、恢復執行
              可以使用 g 命令回覆程式的執行。

     3、單步調試代碼
          當我們調試程式的時候,最多的時候是使用 Visual Studio 的 f10、f11、f5這樣的命令,在 Windbg 中也有類似的命令可以使用。
        
  3.1、p 命令
              p(step):命令其實就是VS 中的 f10 快捷鍵,單步執行,遇到函數也是當成一條指令執行,不會進入函數體。
              
          3.2、t 命令
              
t(trace):命令其實就是 VS 的 f11 快捷鍵,它是一種進入函數的單步執行調試。
              
          3.3、pc 命令
              pc(Step to Next Call)    就是一直運行直到遇到 call 為止,不會進入函數體,call 是一個函數調用,彙編指令。
              
          3.4、tc 命令
           
tc(Trace to Next Call)    和 pc 不同的是,tc 會進入方法體,直到遇到 call 為止。

          3.5、pt 命令
              pt(Step to Next Return)    遇到下一個 ret 為止。   
              
          3.6、tt 命令
              tt(Trace to Next Return)    會進入函數體直到遇到 ret 為止。遞歸的意思。
              
    4、退出測試會話
          結束調試會話,有兩個目的,看是否保留程式的執行。
          4.1、q(quit):結束調試會話+調試程式退出
              調試會話結束,應用程式也會退出。
          4.2、qd(quit and detach):結束調試會話+調試程式繼續運行
              調試會話結束,應用程式保持運行態,不會退出。

三、調試過程
    
廢話不多說,這一節是具體的調試操作的過程,又可以說是眼見為實的過程,在開始之前,我還是要啰嗦兩句,這一節分為兩個部分,第一部分是測試的源碼部分,沒有代碼,當然就談不上測試了,調試必須有載體。第二部分就是根據具體的代碼來證實我們學到的知識,是具體的眼見為實。
    1、測試源碼
        
1.1、Example_4_1_1
 1 namespace Example_4_1_1
 2 {
 3     internal class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             for (int i = 0; i < int.MaxValue; i++)
 8             {
 9                 Console.WriteLine($"i={i}");
10                 Thread.Sleep(1000);
11             }
12             Console.ReadLine();
13         }
14     }
15 }
View Code         1.2、Example_4_1_2
 1 namespace Example_4_1_2
 2 {
 3     internal class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Debugger.Break();
 8 
 9             int a = 10;
10             int b = 12;
11 
12             var sum = a + b;
13 
14             Console.WriteLine($"sum={sum}");
15 
16             Console.ReadLine();
17         }
18     }
19 }
View Code         1.3、Example_4_1_3
 1 namespace Example_4_1_3
 2 {
 3     internal class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Run();
 8 
 9             Console.ReadLine();
10         }
11 
12         static void Run()
13         {
14             Console.WriteLine("請輸入一個除數:");
15             var num = Console.ReadLine();
16             var result = 10 / Convert.ToInt32(num);
17         }
18     }
19 }
View Code         1.4、Example_4_1_4
 1 namespace Example_4_1_4
 2 {
 3     internal class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Sum1(10);
 8             Debugger.Break();
 9 
10             int i = 10;
11             int j = 20;
12 
13             var sum = Sum1(i);
14             Console.WriteLine($"sum={sum}");
15 
16             Console.ReadLine();
17         }
18 
19         private static int Sum1(int a)
20         {
21             var i = a;
22             var j = 11;
23             int sum = Sum2(i, j);
24 
25             return sum;
26         }
27 
28         private static int Sum2(int a, int b)
29         {
30             var i = a;
31             var j = b;
32             var k = 13;
33 
34             var sum = Sum3(i, j, k);
35             return sum;
36         }
37 
38         private static int Sum3(int i, int j, int k)
39         {
40             return i + j + k;
41         }
42     }
43 }
View Code
    2、眼見為實
          2.1、Windbg【Attach to Process】附加進程,通過 int 3 命令中斷程式。
              測試代碼:Example_4_1_1
            程式很簡單,直接運行 exe 程式,打開 Windbg,點擊菜單【attach to process】進入調試器界面。其實什麼操作都不用做,我們就可以看到調試器的輸出結果。特別強調,紅色標註的就是 int 3中斷。
1 ModLoad: 6fa30000 6faba000   C:\Windows\Microsoft.NET\Framework\v4.0.30319\clrjit.dll
2 ModLoad: 75f50000 75feb000   C:\Windows\System32\OLEAUT32.dll
3 (5384.3250): Break instruction exception - code 80000003 (first chance)
4 eax=00270000 ebx=00000000 ecx=7790cee0 edx=7790cee0 esi=7790cee0 edi=7790cee0
5 eip=778d3410 esp=04c2f92c ebp=04c2f958 iopl=0         nv up ei pl zr na pe nc
6 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
7 ntdll!DbgBreakPoint:
8 778d3410 cc              int     3

              當然,我們也可以通過【g】命令,繼續運行程式,然後點擊工具欄的【break】按鈕,程式就進入中斷,這裡的結果和上面是一樣的。

1 0:006> g
2 (5384.528c): Break instruction exception - code 80000003 (first chance)
3 eax=00279000 ebx=00000000 ecx=7790cee0 edx=7790cee0 esi=7790cee0 edi=7790cee0
4 eip=778d3410 esp=04eaf960 ebp=04eaf98c iopl=0         nv up ei pl zr na pe nc
5 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
6 ntdll!DbgBreakPoint:
7 778d3410 cc              int     3

              當然,也可以通過【u】命令,查看 ntdll!DbgBreakPoint的彙編代碼。          

1 0:008> u ntdll!DbgBreakPoint
2 ntdll!DbgBreakPoint:
3 778d3410 cc              int     3
4 778d3411 c3              ret(方法返回)

              我們也可以查看【Disassembly】視圖,截圖如下:
              


            解釋內核態:涉及到內核態的執行,我們也可以通過Windbg 查看,重新在打開一個 Windbg,點擊【文件】----》【Attach kernel】,選擇【local】項,點擊【ok】按鈕,進入調試器界面。然後,我們可以輸入【!idt】命令來查看。
 1 lkd> !idt
 2 
 3 Dumping IDT: fffff80069a91000
 4 
 5 00:    fffff80064b93100 nt!KiDivideErrorFaultShadow
 6 01:    fffff80064b93180 nt!KiDebugTrapOrFaultShadow    Stack = 0xFFFFF80069A959D0
 7 02:    fffff80064b93240 nt!KiNmiInterruptShadow    Stack = 0xFFFFF80069A957D0
 8 03:    fffff80064b932c0 nt!KiBreakpointTrapShadow
 9 04:    fffff80064b93340 nt!KiOverflowTrapShadow
10 ..................

              紅色標註的就是在內核態的中斷函數,我們可以使用【u】命令,查看他的彙編代碼。

 1 lkd> u nt!KiBreakpointTrapShadow
 2 nt!KiBreakpointTrapShadow:
 3 fffff800`64b932c0 f644240801      test    byte ptr [rsp+8],1
 4 fffff800`64b932c5 7467            je      nt!KiBreakpointTrapShadow+0x6e (fffff800`64b9332e)
 5 fffff800`64b932c7 0f01f8          swapgs
 6 fffff800`64b932ca 0faee8          lfence
 7 fffff800`64b932cd 650fba24251890000001 bt  dword ptr gs:[9018h],1
 8 fffff800`64b932d7 720c            jb      nt!KiBreakpointTrapShadow+0x25 (fffff800`64b932e5)
 9 fffff800`64b932d9 65488b242500900000 mov   rsp,qword ptr gs:[9000h]
10 fffff800`64b932e2 0f22dc          mov     cr3,rsp
            解釋:,我們可以通過【~* k】命令,列印出所有線程棧,......表示省略,內容太多,沒必要,顯示重要的就可以了。
              
 1 0:008> ~*k
 2 
 3    0  Id: 5384.4128 Suspend: 1 Teb: 0025e000 Unfrozen
 4  # ChildEBP RetAddr      
 5 00 0057ee00 75942d3b     ntdll!NtDelayExecution+0xc
 6 ......
 7 
 8    1  Id: 5384.22a4 Suspend: 1 Teb: 00261000 Unfrozen
 9  # ChildEBP RetAddr      
10 00 0088fab8 778b0f30     ntdll!NtWaitForWorkViaWorkerFactory+0xc
11 ......
12 
13    2  Id: 5384.3034 Suspend: 1 Teb: 00264000 Unfrozen
14  # ChildEBP RetAddr      
15 00 00affb9c 778b0f30     ntdll!NtWaitForWorkViaWorkerFactory+0xc
16 .......
17 
18    3  Id: 5384.35fc Suspend: 1 Teb: 00267000 Unfrozen
19  # ChildEBP RetAddr      
20 00 00bff9f0 778b0f30     ntdll!NtWaitForWorkViaWorkerFactory+0xc
21 ......
22 
23    4  Id: 5384.3c50 Suspend: 1 Teb: 0026a000 Unfrozen
24  # ChildEBP RetAddr      
25 00 0258f804 75939623     ntdll!NtWaitForMultipleObjects+0xc
26 01 0258f804 711567d7     KERNELBASE!WaitForMultipleObjectsEx+0x103
27 02 0258f86c 711566ff     clr!DebuggerRCThread::MainLoop+0x99
28 03 0258f898 71156620     clr!DebuggerRCThread::ThreadProc+0xd0
29 04 0258f8c4 7711f989     clr!DebuggerRCThread::ThreadProcStatic+0xa3
30 05 0258f8d4 778c7084     KERNEL32!BaseThreadInitThunk+0x19
31 06 0258f930 778c7054     ntdll!__RtlUserThreadStart+0x2f
32 07 0258f940 00000000     ntdll!_RtlUserThreadStart+0x1b
33 
34    5  Id: 5384.2050 Suspend: 1 Teb: 0026d000 Unfrozen
35  # ChildEBP RetAddr      
36 00 0475fabc 75939623     ntdll!NtWaitForMultipleObjects+0xc
37 ......
38 
39    6  Id: 5384.2ce0 Suspend: 1 Teb: 00276000 Unfrozen
40  # ChildEBP RetAddr      
41 00 04c2f84c 778b0f30     ntdll!NtWaitForWorkViaWorkerFactory+0xc
42 ......
43 
44    7  Id: 5384.489c Suspend: 1 Teb: 00273000 Unfrozen
45  # ChildEBP RetAddr      
46 ......
47 04 04d6ffb0 00000000     ntdll!_RtlUserThreadStart+0x1b
48 
49 #  8  Id: 5384.528c Suspend: 1 Teb: 00279000 Unfrozen
50  # ChildEBP RetAddr      
51 00 04eaf98c 7790cf19     ntdll!DbgBreakPoint(int 3 中斷)
52 01 04eaf98c 7711f989     ntdll!DbgUiRemoteBreakin+0x39
53 02 04eaf99c 778c7084     KERNEL32!BaseThreadInitThunk+0x19
54 03 04eaf9f8 778c7054     ntdll!__RtlUserThreadStart+0x2f
55 04 04eafa08 00000000     ntdll!_RtlUserThreadStart+0x1b


          2.2、使用WinDbg 啟動程式,在進程初始化函數中斷進程。
              測試代碼:Example_4_1_2
            
我們編譯項目,打開 Windbg,點擊【文件】----》【launch executable】附加程式,打開調試器的界面,程式已經處於中斷狀態。我們可以看到,如下輸出:
 1 Executable search path is: 
 2 ModLoad: 00be0000 00be8000   Example_4_1_2.exe
 3 ModLoad: 77860000 77a02000   ntdll.dll
 4 ModLoad: 717e0000 71832000   C:\Windows\SysWOW64\MSCOREE.DLL
 5 ModLoad: 77100000 771f0000   C:\Windows\SysWOW64\KERNEL32.dll
 6 ModLoad: 75820000 75a33000   C:\Windows\SysWOW64\KERNELBASE.dll
 7 ModLoad: 5efe0000 5f07f000   C:\Windows\SysWOW64\apphelp.dll
 8 (300c.20b8): Break instruction exception - code 80000003 (first chance)
 9 eax=00000000 ebx=00000000 ecx=534d0000 edx=00000000 esi=77871f64 edi=7787252c
10 eip=77910de2 esp=00f7f824 ebp=00f7f850 iopl=0         nv up ei pl zr na pe nc
11 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
12 ntdll!LdrpDoDebuggerBreak+0x2b:
13 77910de2 cc              int     3

              紅色部分需要註意,然後我們使用【u】命令查看它的彙編代碼。

 1 0:000> u ntdll!LdrpDoDebuggerBreak+0x2b
 2 ntdll!LdrpDoDebuggerBreak+0x2b:
 3 77910de2 cc              int     3
 4 77910de3 eb07            jmp     ntdll!LdrpDoDebuggerBreak+0x35 (77910dec)
 5 77910de5 33c0            xor     eax,eax
 6 77910de7 40              inc     eax
 7 77910de8 c3              ret
 8 77910de9 8b65e8          mov     esp,dword ptr [ebp-18h]
 9 77910dec c745fcfeffffff  mov     dword ptr [ebp-4],0FFFFFFFEh
10 77910df3 8b4df0          mov     ecx,dword ptr [ebp-10h]

              我們可以使用【k】命令,繼續查看。

1 0:000> k
2  # ChildEBP RetAddr      
3 00 00f7f850 7790b2f8     ntdll!LdrpDoDebuggerBreak+0x2b(int 3 中斷)
4 01 00f7fab0 778ba3d1     ntdll!LdrpInitializeProcess+0x1c98(進程初始化的時候執行的 break中斷,)
5 02 00f7fb08 778ba2c1     ntdll!_LdrpInitialize+0xba
6 03 00f7fb14 00000000     ntdll!LdrInitializeThunk+0x11

               ntdll是一個網關函數dll,如果想使用內核的功能幾必須通過 ntdll 裡面的函數。ntdll!LdrpDoDebuggerBreak 這個中斷是在進程初始化之前進行的,是很早的一個時機,載入的東西也不多,只有【Example_4_1_2.exentdll.dllMSCOREE.DLLKERNEL32.dll...】,之所以這樣,可以讓我們設置一些或者說配置一些初始化的東西,比如:載入 SOS等。

            
        
2.3、使用 bp 命令給程式下斷點,可以讓程式中斷。
            
測試代碼:Example_4_1_2
            比如,我們在【int a = 10;】這樣代碼下斷點,行數:12.
            

               我們編譯項目,打開 Windbg,點擊【文件】----》【launch executable】附加程式,打開調試器的界面,程式已經處於中斷狀態。我們使用【g】命令,繼續運行,然後我們使用【!clrstack】命令,查看線程棧。

1 0:000> !clrstack
2 OS Thread Id: 0x3c54 (0)
3 Child SP       IP Call Site
4 00d5ed38 7597f262 [HelperMethodFrame: 00d5ed38] System.Diagnostics.Debugger.BreakInternal()
5 00d5edb4 7064f195 System.Diagnostics.Debugger.Break() [f:\dd\ndp\clr\src\BCL\system\diagnostics\debugger.cs @ 91]
6 00d5eddc 02ba0886 Example_4_1_2.Program.Main(System.String[]) [E:\Visual Studio 2022\...\Example_4_1_2\Program.cs @ 10]
7 00d5ef78 70faf036 [GCFrame: 00d5ef78] 

                紅色標註的是 Main 方法的地址,然後執行【!u 02ba0886】命令,查看他的彙編代碼。

1 0:000> !u 02ba0886
2 Normal JIT generated code
3 Example_4_1_2.Program.Main(System.String[])
4 Begin 02ba0848, size a3
5 
6 ......
7 
8 E:\Visual Studio 2022\...\Example_4_1_2\Program.cs @ 12:(這個行號就是C# 代碼的行號)
9 02ba0887 c745f00a000000  mov     dword ptr [ebp-10h],0Ah

                我們找到了代碼的位置,就可以下斷點了,使用【bp】命令。

0:000> bp 02ba0887

                【g】繼續運行,就會到斷點出暫停。

              

                效果如圖。


        
2.4、觸發異常,也可以讓程式中斷。
            
測試代碼:Example_4_1_3
              代碼很簡單,我簡單說一些流程,我們首先將要測試的項目編譯好,然後打開 Windbg,通過【launch executable】附加應用程式,調試器會響應一個 int 3中斷,我們通過【g】命令,繼續運行程式。程式提示輸入一個數字,我輸入0,肯定就會異常了。
           效果如圖:
           

              異常中斷的代碼是:014b08ea f77df4         idiv    eax, dword ptr [ebp-0Ch],效果如圖:
              
              我們使用【dp】命令,查看【ebp-0Ch】代碼的值。

1 0:000> dp ebp-0Ch l1
2 012ff2fc  00000000

              我們可以使用【dp】命令,也可以使用【?】命令,查看一下eax 是什麼,其實 eax就是十進位的10。

1 0:000> ? eax
2 Evaluate expression: 10 = 0000000a

              代碼【idiv】就是表示除法觸發的異常。
              我們也可以使用【k】命令,查看調用棧,也能看出在哪裡中斷。

1 0:000> k
2  # ChildEBP RetAddr      
3 00 012ff308 014b086b     Example_4_1_3!COM+_Entry_Point <PERF> (Example_4_1_3+0x6308ea) [E:\...\Example_4_1_3\Program.cs @ 18] 
4 01 012ff318 7077f036     Example_4_1_3!COM+_Entry_Point <PERF> (Example_4_1_3+0x63086b) [E:\...\Example_4_1_3\Program.cs @ 9] 
5 ......
6 0f 012ffde4 77057054     ntdll!__RtlUserThreadStart+0x2f
7 10 012ffdf4 00000000     ntdll!_RtlUserThreadStart+0x1b

              紅色部分就是中斷的 C# 代碼的行號。


          2.5、單步調試命令測試。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 響應數據 @ResponseBody 類型:方法註解、類註解 位置:Controller方法、類上 作用:將方法返回值直接響應,如果返回值類型是 實體對象/集合 ,將會轉換為json格式響應 說明:@RestController = @Controller + @ResponseBody 統一響應結 ...
  • 大家普遍認知中,字元串拼接要使用StringBuilder,那為什麼idea會建議你是用“+”呢,那到底StringBuilder 和 “+”有什麼具體區別呢,我們一起來探究一下。 ...
  • /** * 1、業務場景 * 1、定時執行時,可能出現數據量大,執行不完,線程直接被終止掉,丟數據。 */ import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; ...
  • 本人是tex新手,如果各位大佬有更好的方法歡迎分享,不勝感激。 適用情況 本文適用於使用\begin{thebibliography}和\bibitem排序的情況,如果使用bibtex排序那麼網上很多教程。 在使用tex發現不會自動排序非常僵硬,即如下情況: 在參考文獻的位置引用排在第二個,但是在原 ...
  • 物以類聚,聚類演算法使用最優化的演算法來計算數據點之間的距離,並將它們分組到最近的簇中。 Scipy的聚類模塊中,進一步分為兩個聚類子模塊: vq(vector quantization):提供了一種基於向量量化的聚類演算法。 vq模塊支持多種向量量化演算法,包括K-means、GMM(高斯混合模型)和WA ...
  • 馬哥原創:用Python採集小紅書評論,抓取欄位包含:筆記鏈接,頁碼,評論者昵稱,評論者id,評論者主頁鏈接,評論時間,評論IP屬地,評論點贊數,評論級別,評論內容。 ...
  • 在C#中,List集合是一種泛型集合,可以存儲任何類型的對象。克隆一個List集合可以通過以下幾種方式實現: 使用List的構造函數 使用List的構造函數可以創建一個新的List對象,並將原始List中的元素複製到新List中。例如: List<int> list1 = new List<int> ...
  • 在C#中,字典(Dictionary)是一種特殊的集合,用於存儲鍵/值對。這是一種關聯數組,其中每個元素都包含一個鍵(Key)和一個值(Value)。 下麵是一個簡單的C#字典的例子: //字典:泛型;key - value,增刪查改 都很快; // 字典如果數據量太大的話,也會影響效率. // 字 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...