用戶態到內核態:Linux信號傳遞的九重門(二)

1. 保存信號

1.1. 信號其他相關常見概念

  • 實際執?信號的處理動作稱為信號遞達(Delivery)。
  • 信號從產?到遞達之間的狀態,稱為信號未決(Pending)。
  • 進程可以選擇阻塞 (Block )某個信號。
  • 被阻塞的信號產?時將保持在未決狀態,直到進程解除對此信號的阻塞,才執?遞達的動作。

1.2. 在內核中的表示

?信號在內核中的表?意圖

  • 每個信號都有兩個標志位分別表?阻塞(block)和未決(pending),還有?個函數指針表?處理動作。信號產?時,內核在進程控制塊中設置該信號的未決標志,直到信號遞達才清除該標志。在上圖的例?中,SIGHUP信號未阻塞也未產?過,當它遞達時執?默認處理動作。
  • SIGINT信號產?過,但正在被阻塞,所以暫時不能遞達。雖然它的處理動作是忽略,但在沒有解除阻塞之前不能忽略這個信號,因為進程仍有機會改變處理動作之后再解除阻塞。
  • SIGQUIT信號未產?過,?旦產?SIGQUIT信號將被阻塞,它的處理動作是???定義函數sighandler。
// 內核結構 2.6.18
struct task_struct
{/* signal handlers */struct sighand_struct *sighand;sigset_t blocked struct sigpending pending;
};struct sighand_struct
{atomic_t count;struct k_sigaction action[_NSIG]; // #define _NSIG 64spinlock_t siglock;
};struct __new_sigaction
{__sighandler_t sa_handler;unsigned long sa_flags;void (*sa_restorer)(void); /* Not used by Linux/SPARC */__new_sigset_t sa_mask;
};struct k_sigaction
{struct __new_sigaction sa;void __user *ka_restorer;
};/* Type of a signal handler. */
typedef void (*__sighandler_t)(int);
struct sigpending
{struct list_head list;sigset_t signal;
};

1.3. sigset_t

從上圖來看,每個信號只有?個bit的未決標志, ?0即1, 不記錄該信號產?了多少次,阻塞標志也是這樣表?的。因此, 未決和阻塞標志可以?相同的數據類型sigset_t來存儲, , 這個類型可以表?每個信號的“有效”或“?效”狀態, 在阻塞信號集中“有效”和“?效”的含義是該信號是否被阻塞, ?在未決信號集中“有效”和“?效”的含義是該信號是否處于未決狀態。下?節將詳細介紹信號集的各種操作。阻塞信號集也叫做當前進程的 這?的“屏蔽”應該理解為阻塞?不是忽略。

1.4. 信號集操作函數

sigset_t類型對于每種信號??個bit表?“有效”或“?效”狀態, ?于這個類型內部如何存儲這些
bit則依賴于系統實現, 從使?者的?度是不必關?的, 使?者只能調?以下函數來操作sigset_ t變量,?不應該對它的內部數據做任何解釋, ?如?printf直接打印sigset_t變量是沒有意義的。
#include <signal.h>int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
  • 函數sigemptyset初始化set所指向的信號集,使其中所有信號的對應bit清零,表?該信號集不包含任何有效信號。
  • 函數sigfillset初始化set所指向的信號集,使其中所有信號的對應bit置位,表? 該信號集的有效信號包括系統?持的所有信號。
  • 注意,在使?sigset_ t類型的變量之前,?定要調 ?sigemptyset或sigfillset做初始化,使信號集處于確定的狀態。初始化sigset_t變量之后就可以在調?sigaddset和sigdelset在該信號集中添加或刪除某種有效信號。

這四個函數都是成功返回0,出錯返回-1。sigismember是?個布爾函數,?于判斷?個信號集的有效信號中是否包含 某種信號,若包含則返回1,不包含則返回0,出錯返回-1。

1.4.1. sigprocmask

調?函數 sigprocmask 可以讀取或更改進程的信號屏蔽字(阻塞信號集)。
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);返回值:若成功則為0,若出錯則為-1
如果oset是?空指針,則讀取進程的當前信號屏蔽字通過oset參數傳出。如果set是?空指針,則更改
進程的信號屏蔽字,參數how指?如何更改。如果oset和set都是?空指針,則先將原來的信號屏蔽字備份到oset?,然后 根據set和how參數更改信號屏蔽字。假設當前的信號屏蔽字為mask,下表說明了how參數的可選值。
如果調?sigprocmask解除了對當前若?個未決信號的阻塞,則在sigprocmask返回前,?少將其中?
個信號遞達。

1.4.2. sigpending

#include <signal.h>
int sigpending(sigset_t *set);讀取當前進程的未決信號集,通過set參數傳出。
調?成功則返回0,出錯則返回-1

1.5. 測試相關函數

測試代碼:

#include <iostream>
#include <unistd.h>
#include <cstdio>
#include <sys/types.h>
#include <sys/wait.h>void Printpending(const sigset_t &pending)
{std::cout << "curr process[" << getpid() << "]pending";for (int i = 31; i >= 1; i--){if (sigismember(&pending, i) == 1){std::cout << "1";}else{std::cout << "0";}}std::cout<<std::endl;
}void handler(int signum)
{std::cout << "第" << signum << "號信號被遞達!" << std::endl;std::cout << "------------------------------------" << std::endl;sigset_t pending;Printpending(pending);std::cout << "------------------------------------" << std::endl;
}int main()
{// Step1. 捕捉2號信號signal(2, handler);// Step2. 屏蔽2號信號sigset_t old_set, set;// 只是把用戶級別的sigset_t置空,內核block沒有置空。sigemptyset(&old_set);sigemptyset(&set);sigaddset(&set, 2);int ret = sigprocmask(SIG_BLOCK, &set, &old_set);int cnt = 15;while (true){sigset_t pending;sigpending(&pending);cnt--;Printpending(pending);if (cnt == 0){std::cout << "解除對2號信號的屏蔽!!!" << std::endl;sigprocmask(SIG_SETMASK, &old_set, &set);}sleep(1);}return 0;
}

測試結果:

2. 捕捉信號

2.1. 信號捕捉的流程

?如果信號的處理動作是???定義函數,在信號遞達時就調?這個函數,這稱為捕捉信號。

?由于信號處理函數的代碼是在??空間的,處理過程?較復雜,舉例如下:

  • ??程序注冊了 SIGQUIT 信號的處理函數 sighandler
  • 當前正在執? main 函數,這時發?中斷或異常切換到內核態。
  • 在中斷處理完畢后要返回??態的 main 函數之前檢查到有信號 SIGQUIT 遞達。
  • 內核決定返回??態后不是恢復 main 函數的上下?繼續執?,?是執? sighandler
    數, sighandler main 函數使?不同的堆棧空間,它們之間不存在調?和被調?的關系,是兩個獨?的控制流程。
  • ??????sighandler 函數返回后?動執?特殊的系統調? sigreturn 再次進?內核態。
  • 如果沒有新的信號要遞達,這次再返回??態就是恢復 main 函數的上下?繼續執?了。

?2.2. sigaction

#include <signal.h>
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
  • sigaction函數可以讀取和修改與指定信號相關聯的處理動作。調?成功則返回0,出錯則返回- 1。signo是指定信號的編號。若act指針?空,則根據act修改該信號的處理動作。若oact指針?空, 則通過oact傳出該信號原來的處理動作。act和oact指向sigaction結構體
  • 將sa_handler賦值為常數SIG_IGN傳給sigaction表?忽略信號,賦值為常數SIG_DFL表?執?系統默認動作,賦值為?個函數指針表???定義函數捕捉信號,或者說向內核注冊了?個信號處理函數,該函數返回值為void,可以帶?個int參數,通過參數可以得知當前信號的編號,這樣就可以?同?個函數處理多種信號。顯然,這也是?個回調函數,不是被main函數調?,?是被系統所調?。

當某個信號的處理函數被調?時,內核?動將當前信號加?進程的信號屏蔽字,當信號處理函數返回時?動恢復原來的信號屏蔽字,這樣就保證了在處理某個信號時,如果這種信號再次產?,那么 它會被阻塞到當前處理結束為?。 如果在調?信號處理函數時,除了當前信號被?動屏蔽之外,還希望?動屏蔽另外?些信號,則?sa_mask字段說明這些需要額外屏蔽的信號,當信號處理函數返回時?動恢復原來的信號屏蔽字。

2.3. OS是怎么運行的

2.3.1. 硬件中斷

  • 操作系統自己維護了一張中斷向量表,用于處理各種中斷。中斷向量表屬于操作系統的一部分,啟動的時候就加載到內存之中了。
  • ?通過外部硬件中斷,操作系統就不需要對外設進?任何周期性的檢測或者輪詢。
  • 由外部設備觸發的,中斷系統運?流程,叫做硬件中斷。
// Linux內核0.11源碼
void trap_init(void)
{int i;set_trap_gate(0, &divide_error); // 設置除操作出錯的中斷向量值。以下雷同。set_trap_gate(1, &debug);set_trap_gate(2, &nmi);set_system_gate(3, &int3); /* int3-5 can be called from all */set_system_gate(4, &overflow);set_system_gate(5, &bounds);set_trap_gate(6, &invalid_op);set_trap_gate(7, &device_not_availab);// Linux內核0.11源碼void trap_init(void){int i;set_trap_gate(0, &divide_error); // 設置除操作出錯的中斷向量值。以下雷同。set_trap_gate(1, &debug);set_trap_gate(2, &nmi);set_system_gate(3, &int3); /* int3-5 can be called from all */set_system_gate(4, &overflow);set_system_gate(5, &bounds);set_trap_gate(6, &invalid_op);set_trap_gate(7, &device_not_availab);}for (i = 17; i < 48; i++)set_trap_gate(i, &reserved);set_trap_gate(45, &irq13);              // 設置協處理器的陷阱?。outb_p(inb_p(0x21) & 0xfb, 0x21);       // 允許主8259A 芯?的IRQ2 中斷請求。outb(inb_p(0xA1) & 0xdf, 0xA1);         // 允許從8259A 芯?的IRQ13 中斷請求。set_trap_gate(39, &parallel_interrupt); // 設置并??的陷阱?。
}void rs_init(void)
{set_intr_gate(0x24, rs1_interrupt); // 設置串??1 的中斷?向量(硬件IRQ4 信號)。set_intr_gate(0x23, rs2_interrupt); // 設置串??2 的中斷?向量(硬件IRQ3 信號)。init(tty_table[1].read_q.data);     // 初始化串??1(.data 是端?號)。init(tty_table[2].read_q.data);     // 初始化串??2。outb(inb_p(0x21) & 0xE7, 0x21);     // 允許主8259A 芯?的IRQ3,IRQ4 中斷信號請求。
}

?2.3.2. 時鐘中斷

操作系統在硬件的推動下,自動調度。

// Linux 內核0.11
// main.c
sched_init(); // 調度程序初始化(加載了任務0 的tr, ldtr) (kernel/sched.c)
// 調度程序的初始化?程序。
void sched_init(void)
{... set_intr_gate(0x20, &timer_interrupt);// 修改中斷控制器屏蔽碼,允許時鐘中斷。outb(inb_p(0x21) & ~0x01, 0x21);// 設置系統調?中斷?。set_system_gate(0x80, &system_call);...
}
// system_call.s
_timer_interrupt : ...; // do_timer(CPL)執?任務切換、計時等?作,在kernel/shched.c,305 ?實現。
call _do_timer;         // 'do_timer(long CPL)' does everything from
// 調度??
void do_timer(long cpl)
{... schedule();
}
void schedule(void)
{... switch_to(next); // 切換到任務號為next 的任務,并運?之。
}

2.3.3. 死循環

我們可以將操作系統理解成一個死循環。

void main(void) /* 這?確實是void,并沒錯。 */
{ /* 在startup 程序(head.s)中就是這樣假設的。 */.../** 注意!! 對于任何其它的任務,'pause()'將意味著我們必須等待收到?個信號才會返* 回就緒運?態,但任務0(task0)是唯?的意外情況(參?'schedule()'),因為任* 務0 在任何空閑時間?都會被激活(當沒有其它任務在運?時),* 因此對于任務0'pause()'僅意味著我們返回來查看是否有其它任務可以運?,如果沒* 有的話我們就回到這?,?直循環執?'pause()'。*/for (;;)pause();
} // end main

這樣,操作系統,就在硬件時鐘的推動下,進行自動調度。

2.3.4. 軟中斷

  • 上述外部硬件中斷,需要硬件設備觸發。
  • 為了讓操作系統?持進?系統調?,CPU也設計了對應的匯編指令(int 或者 syscall),可以讓CPU內部觸發中斷邏輯。(軟中斷)
    系統調用的過程 其實就是先int 0x80、syscall陷?內核,本質就是觸發軟中斷,CPU就會?動執 ?系統調?的處理?法,?這個?法會根據系統調?號,?動查表,執?對應的?法。
系統調用號的本質就是數組下標!
// sys.h
// 系統調?函數指針表。?于系統調?中斷處理程序(int 0x80),作為跳轉表。
extern int sys_setup (); // 系統啟動初始化設置函數。 (kernel/blk_drv/hd.c,71)
extern int sys_exit (); // 程序退出。 (kernel/exit.c, 137)
extern int sys_fork (); // 創建進程。 (kernel/system_call.s, 208)
extern int sys_read (); // 讀?件。 (fs/read_write.c, 55)
extern int sys_write (); // 寫?件。 (fs/read_write.c, 83)
extern int sys_open (); // 打開?件。 (fs/open.c, 138)
extern int sys_close (); // 關閉?件。 (fs/open.c, 192)
extern int sys_waitpid (); // 等待進程終?。 (kernel/exit.c, 142)
extern int sys_creat (); // 創建?件。 (fs/open.c, 187)
extern int sys_link (); // 創建?個?件的硬連接。 (fs/namei.c, 721)
extern int sys_unlink (); // 刪除?個?件名(或刪除?件)。 (fs/namei.c, 663)
extern int sys_execve (); // 執?程序。 (kernel/system_call.s, 200)
extern int sys_chdir (); // 更改當前?錄。 (fs/open.c, 75)
extern int sys_time (); // 取當前時間。 (kernel/sys.c, 102)
extern int sys_mknod (); // 建?塊/字符特殊?件。 (fs/namei.c, 412)
extern int sys_chmod (); // 修改?件屬性。 (fs/open.c, 105)
extern int sys_chown (); // 修改?件宿主和所屬組。 (fs/open.c, 121)
extern int sys_break (); // (-kernel/sys.c, 21)
extern int sys_stat (); // 使?路徑名取?件的狀態信息。 (fs/stat.c, 36)
extern int sys_lseek (); // 重新定位讀/寫?件偏移。 (fs/read_write.c, 25)
extern int sys_getpid (); // 取進程id。 (kernel/sched.c, 348)
extern int sys_mount (); // 安裝?件系統。 (fs/super.c, 200)
extern int sys_umount (); // 卸載?件系統。 (fs/super.c, 167)
extern int sys_setuid (); // 設置進程??id。 (kernel/sys.c, 143)
extern int sys_getuid (); // 取進程??id。 (kernel/sched.c, 358)
extern int sys_stime (); // 設置系統時間?期。 (-kernel/sys.c, 148)
extern int sys_ptrace (); // 程序調試。 (-kernel/sys.c, 26)
extern int sys_alarm (); // 設置報警。 (kernel/sched.c, 338)
extern int sys_fstat (); // 使??件句柄取?件的狀態信息。(fs/stat.c, 47)
extern int sys_pause (); // 暫停進程運?。 (kernel/sched.c, 144)
extern int sys_utime (); // 改變?件的訪問和修改時間。 (fs/open.c, 24)
extern int sys_stty (); // 修改終端?設置。 (-kernel/sys.c, 31)
extern int sys_gtty (); // 取終端?設置信息。 (-kernel/sys.c, 36)
extern int sys_access (); // 檢查??對?個?件的訪問權限。(fs/open.c, 47)
extern int sys_nice (); // 設置進程執?優先權。 (kernel/sched.c, 378)
extern int sys_ftime (); // 取?期和時間。 (-kernel/sys.c,16)
extern int sys_sync (); // 同步?速緩沖與設備中數據。 (fs/buffer.c, 44)
extern int sys_kill (); // 終??個進程。 (kernel/exit.c, 60)
extern int sys_rename (); // 更改?件名。 (-kernel/sys.c, 41)
extern int sys_mkdir (); // 創建?錄。 (fs/namei.c, 463)
extern int sys_rmdir (); // 刪除?錄。 (fs/namei.c, 587)
extern int sys_dup (); // 復制?件句柄。 (fs/fcntl.c, 42)
extern int sys_pipe (); // 創建管道。 (fs/pipe.c, 71)
extern int sys_times (); // 取運?時間。 (kernel/sys.c, 156)
extern int sys_prof (); // 程序執?時間區域。 (-kernel/sys.c, 46)
extern int sys_brk (); // 修改數據段?度。 (kernel/sys.c, 168)
extern int sys_setgid (); // 設置進程組id。 (kernel/sys.c, 72)
extern int sys_getgid (); // 取進程組id。 (kernel/sched.c, 368)
extern int sys_signal (); // 信號處理。 (kernel/signal.c, 48)
extern int sys_geteuid (); // 取進程有效??id。 (kenrl/sched.c, 363)
extern int sys_getegid (); // 取進程有效組id。 (kenrl/sched.c, 373)
extern int sys_acct (); // 進程記帳。 (-kernel/sys.c, 77)
extern int sys_phys (); // (-kernel/sys.c, 82)
extern int sys_lock (); // (-kernel/sys.c, 87)
extern int sys_ioctl (); // 設備控制。 (fs/ioctl.c, 30)
extern int sys_fcntl (); // ?件句柄操作。 (fs/fcntl.c, 47)
extern int sys_mpx (); // (-kernel/sys.c, 92)
extern int sys_setpgid (); // 設置進程組id。 (kernel/sys.c, 181)
extern int sys_ulimit (); // (-kernel/sys.c, 97)
extern int sys_uname (); // 顯?系統信息。 (kernel/sys.c, 216)
extern int sys_umask (); // 取默認?件創建屬性碼。 (kernel/sys.c, 230)
extern int sys_chroot (); // 改變根系統。 (fs/open.c, 90)
extern int sys_ustat (); // 取?件系統信息。 (fs/open.c, 19)
extern int sys_dup2 (); // 復制?件句柄。 (fs/fcntl.c, 36)
extern int sys_getppid (); // 取?進程id。 (kernel/sched.c, 353)
extern int sys_getpgrp (); // 取進程組id,等于getpgid(0)。(kernel/sys.c, 201)
extern int sys_setsid (); // 在新會話中運?程序。 (kernel/sys.c, 206)
extern int sys_sigaction (); // 改變信號處理過程。 (kernel/signal.c, 63)
extern int sys_sgetmask (); // 取信號屏蔽碼。 (kernel/signal.c, 15)
extern int sys_ssetmask (); // 設置信號屏蔽碼。 (kernel/signal.c, 20)
extern int sys_setreuid (); // 設置真實與/或有效??id。 (kernel/sys.c,118)
extern int sys_setregid (); // 設置真實與/或有效組id。 (kernel/sys.c, 51)// 系統調?函數指針表。?于系統調?中斷處理程序(int 0x80),作為跳轉表。
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,sys_setreuid, sys_setregid
};

我們平時寫代碼的時候用系統調用,并不會直接在用戶層使用int 0x80或者syscall因為Linux的gnu C標準庫,給我們把?乎所有的系統調?全部封裝了。

2.3.5. 缺頁中斷,除0錯誤,野指針錯誤,內存碎片處理

void trap_init(void)
{int i;set_trap_gate(0,&divide_error);// 設置除操作出錯的中斷向量值。以下雷同。set_trap_gate(1,&debug);set_trap_gate(2,&nmi);set_system_gate(3,&int3); /* int3-5 can be called from all */set_system_gate(4,&overflow);set_system_gate(5,&bounds);set_trap_gate(6,&invalid_op);set_trap_gate(7,&device_not_available);set_trap_gate(8,&double_fault);set_trap_gate(9,&coprocessor_segment_overrun);set_trap_gate(10,&invalid_TSS);set_trap_gate(11,&segment_not_present);set_trap_gate(12,&stack_segment);set_trap_gate(13,&general_protection);set_trap_gate(14,&page_fault);set_trap_gate(15,&reserved);set_trap_gate(16,&coprocessor_error);// 下?將int17-48 的陷阱?先均設置為reserved,以后每個硬件初始化時會重新設置??的陷阱?。for (i=17;i<48;i++)set_trap_gate(i,&reserved);set_trap_gate(45,&irq13);// 設置協處理器的陷阱?。outb_p(inb_p(0x21)&0xfb,0x21);// 允許主8259A 芯?的IRQ2 中斷請求。outb(inb_p(0xA1)&0xdf,0xA1);// 允許從8259A 芯?的IRQ13 中斷請求。set_trap_gate(39,&parallel_interrupt);// 設置并??的陷阱?。
}
缺?中斷?內存碎?處理?除零野指針錯誤?這些問題,全部都會被轉換成為CPU內部的軟中斷,
然后?中斷處理例程,完成所有處理。有的是進?申請內存,填充?表,進?映射的。有的是?來
處理內存碎?的,有的是?來給?標進?發送信號,殺掉進程等等。

2.4. 如何理解用戶態和內核態

  • 操作系統?論怎么切換進程,都能找到同?個操作系統!換句話說操作系統系統調??法的執?,是在進程的地址空間中執?的
  • ??態就是執???[0,3]GB時所處的狀態
  • 內核態就是執?內核[3,4]GB時所處的狀態
  • 區分就是按照CPU內的CPL決定,CPL的全稱是Current Privilege Level,即當前特權級別。(用戶態的權限為:11,內核態的權限為:00)
  • ?般執? int 0x80 或者 syscall 軟中斷,CPL會在校驗之后?動變更。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/82809.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/82809.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/82809.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

tar -zxvf jdk-8u212-linux-x64.tar.gz -C /opt/module/這個代碼的解釋

tar -zxvf jdk-8u212-linux-x64.tar.gz -C /opt/module/ 這條命令的解釋如下&#xff1a; 1. tar&#xff1a;這是 Linux 系統中用于歸檔和壓縮文件的命令行工具。 2. -z&#xff1a;表示通過 gzip 壓縮格式來處理文件&#xff0c;因為文件 jdk-8u212-linux-x64.tar.gz 是一個經…

SysAid On-Prem XML注入漏洞復現(CVE-2025-2776)

免責申明: 本文所描述的漏洞及其復現步驟僅供網絡安全研究與教育目的使用。任何人不得將本文提供的信息用于非法目的或未經授權的系統測試。作者不對任何由于使用本文信息而導致的直接或間接損害承擔責任。如涉及侵權,請及時與我們聯系,我們將盡快處理并刪除相關內容。 前…

Nginx的增強與可視化!OpenResty Manager - 現代化UI+高性能反向代理+安全防護

以下是對OpenResty Manager的簡要介紹&#xff1a; OpenResty Manager &#xff08;Nginx 增強版&#xff09;&#xff0c;是一款容易使用、功能強大且美觀的反向代理工具 &#xff0c;可以作為OpenResty Edge 的開源替代品基于 OpenResty 開發&#xff0c;支持并繼承 OpenRes…

旅游推薦數據分析可視化系統——訊飛AI助手(超級v2版本)+論文+數據+源碼

旅游推薦數據分析可視化系統——訊飛AI助手(超級v2版本)論文數據源碼 項目介紹 本項目是一個基于Django框架開發的旅游推薦數據分析可視化系統&#xff0c;集成了訊飛AI大模型助手功能。系統通過對去哪兒網的旅游數據進行采集、分析和可視化&#xff0c;為用戶提供個性化的旅…

大疆無人機(全系列,包括mini)拉流至電腦,實現直播

參考視頻 【保姆級教程】大疆無人機rtmp推流直播教程_嗶哩嗶哩_bilibili VLC使用教程&#xff1a; VLC工具使用指南-CSDN博客 目錄 實現效果&#xff1a; 電腦端 ?編輯 ?編輯 無人機端 VLC拉流 分析 實現效果&#xff1a; (實驗機型&#xff1a;大疆mini4kRC-N2遙控器、大…

windows系統使用phpstudy安裝ssl證書

一、證書準備與上傳 獲取證書文件? 免費證書&#xff08;如阿里云、Lets Encrypt&#xff09;&#xff1a;下載包含.crt&#xff08;證書&#xff09;、.key&#xff08;私鑰&#xff09;、chain.crt&#xff08;證書鏈&#xff09;的文件包 自簽名證書&#xff08;測試用&a…

Spring Validation中9個數據校驗工具

Spring Validation作為Spring生態系統的重要組成部分&#xff0c;提供了一套強大而靈活的數據校驗機制。 1. Bean Validation基礎注解 Spring Validation集成了JSR-380 (Bean Validation 2.0)規范&#xff0c;提供了一系列開箱即用的校驗注解。 常用注解示例 Data public c…

AI 搜索引擎 MindSearch

背景 RAG是一種利用文檔減少大模型的幻覺&#xff0c;AI搜索也是 AI 搜索引擎 MindSearch 是一個開源的 AI 搜索引擎框架&#xff0c;具有與 Perplexity.ai Pro 相同的性能。您可以輕松部署它來構建您自己的搜索引擎&#xff0c;可以使用閉源 LLM&#xff08;如 GPT、Claude…

Java高頻面試之并發編程-16

hello啊&#xff0c;各位觀眾姥爺們&#xff01;&#xff01;&#xff01;本baby今天又來報道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面試官&#xff1a;volatile 實現原理是什么&#xff1f; volatile 關鍵字的實現原理 volatile 是 Java 中用于解決多線程環境下變量可見性…

《零基礎學機器學習》學習大綱

《零基礎學機器學習》學習大綱 《零基礎學機器學習》采用對話體的形式&#xff0c;通過人物對話和故事講解機器學習知識&#xff0c;使內容生動有趣、通俗易懂&#xff0c;降低了學習門檻&#xff0c;豆瓣高分9.1分&#xff0c;作者權威。 接下來的數篇文章&#xff0c;我將用…

C# 中 static的使用

靜態(static)是C#中一個重要的關鍵字&#xff0c;它可以應用于類、方法、屬性和字段。 靜態類 靜態類的特點&#xff1a; 不能實例化只能包含靜態成員密封的&#xff08;sealed&#xff09;,不能被繼承 應用場景&#xff1a; 工具類/輔助類數學計算類&#xff1a;如Math類…

C++藍橋杯真題(題目+解析+流程圖)(特殊運算符+四葉玫瑰數+質因數的個數+最大的矩形紙片+數字游戲+活動人數)

C++藍橋杯真題 藍橋杯省賽C++題目分析1. 特殊運算符題目描述輸入描述輸出描述輸入輸出樣例正確代碼錯誤代碼分析流程圖2. 四葉玫瑰數題目描述輸入描述輸出描述輸入輸出樣例正確代碼錯誤代碼分析流程圖3. 質因數的個數題目描述輸入描述輸出描述輸入輸出樣例正確代碼錯誤代碼分析…

MYSQL 索引與數據結構筆記

MYSQL 索引與數據結構筆記 文章目錄 MYSQL 索引與數據結構筆記1. B-Tree 與 B Tree 基礎對比一、B 樹的優勢二、B 樹的進一步優化三、綜合對比結論 2. MySQL 為何選擇 B Tree3. 索引使用示例與性能分析3.1 整數字段索引查詢3.2 字符字段索引查詢 4. 索引失效與類型轉換陷阱5. 小…

電路中的DGND、GROUND、GROUND_REF的區別,VREF、VCC、VDD、VEE和VSS的區別?

目錄 1 DGND、GROUND、GROUND_REF的區別 1.1 DGND&#xff08;Digital Ground&#xff09; 1.2 GROUND&#xff08;Ground&#xff09; 1.3 GROUND_REF&#xff08;Ground Reference&#xff09; 1.4 區別 2 VREF、VCC、VDD、VEE和VSS的區別 2.1 VREF&#xff08;Refere…

OpenHarmony平臺驅動開發(十),MMC

OpenHarmony平臺驅動開發&#xff08;十&#xff09; MMC 概述 功能簡介 MMC&#xff08;MultiMedia Card&#xff09;即多媒體卡&#xff0c;是一種用于固態非易失性存儲的小體積大容量的快閃存儲卡。 MMC后續泛指一個接口協定&#xff08;一種卡式&#xff09;&#xff0…

C++ 的 VS 項目中引入跨平臺包管理工具 conan

我們知道 C 不像很多其他語言有包管理工具&#xff0c;比如 Python 有 pip&#xff0c;Java 有 maven&#xff0c;C# 有 nuget&#xff0c;JS 有 npm&#xff0c;Go 有 go mod&#xff0c;Rust 有 cargo&#xff0c;項目中需要自己手動引入第三方庫&#xff0c;手動維護帶來了很…

vscode 默認環境路徑

1.下面放在項目根目錄上&#xff1a; .vscode/settings.json 2.settings.json內容&#xff1a; {"python.analysis.extraPaths": ["${workspaceFolder}"],"python.defaultInterpreterPath": "/shared_disk/users/lbg/envs/py310_see3d/b…

Android 項目中配置了多個 maven 倉庫,但依賴還是下載失敗,除了使用代理,還有其他方法嗎?

文章目錄 前言解決方案gradlemaven 倉庫 前言 我們在Android 開發的過程中&#xff0c;經常會遇到三方依賴下載不下來的問題。一般情況下我們會在項目的build.gradle文件中配置多個 maven 倉庫來解決。 // Top-level build file where you can add configuration options com…

uni-app 引入vconsole web端正常,安卓端報錯 Cannot read property ‘sendBeacon‘ of undefined

reportJSException >>>> exception function:createInstanceContext, exception:white screen cause create instanceContext failed,check js stack ->Uncaught TypeError: Cannot read property sendBeacon of undefined vconsole 只支持 web 端&#xff0c;…

火山RTC 7 獲得遠端裸數據

一、獲得遠端裸數據 1、獲得h264數據 1&#xff09;、遠端編碼后視頻數據監測器 /*** locale zh* type callback* region 視頻管理* brief 遠端編碼后視頻數據監測器<br>* 注意&#xff1a;回調函數是在 SDK 內部線程&#xff08;非 UI 線程&#xff09;同步拋出來的&a…