主頁 >  其他 > 答應我,這次搞懂 I/O 多路復用!

答應我,這次搞懂 I/O 多路復用!

2021-04-14 10:18:37 其他

這次,我們以最簡單 socket 網路模型,一步一步的過度到 I/O 多路復用,

但我不會具體細節說到每個系統呼叫的引數,這方面書上肯定比我說的詳細,

好了,發車!


最基本的 Socket 模型

要想客戶端和服務器能在網路中通信,那必須得使用 Socket 編程,它是行程間通信里比較特別的方式,特別之處在于它是可以跨主機間通信,

Socket 的中文名叫作插口,咋一看還挺迷惑的,事實上,雙方要進行網路通信前,各自得創建一個 Socket,這相當于客戶端和服務器都開了一個“口子”,雙方讀取和發送資料的時候,都通過這個“口子”,這樣一看,是不是覺得很像弄了一根網線,一頭插在客戶端,一頭插在服務端,然后進行通信,

創建 Socket 的時候,可以指定網路層使用的是 IPv4 還是 IPv6,傳輸層使用的是 TCP 還是 UDP,

UDP 的 Socket 編程相對簡單些,這里我們只介紹基于 TCP 的 Socket 編程,

服務器的程式要先跑起來,然后等待客戶端的連接和資料,我們先來看看服務端的 Socket 編程程序是怎樣的,

服務端首先呼叫 socket() 函式,創建網路協議為 IPv4,以及傳輸協議為 TCP 的 Socket ,接著呼叫 bind() 函式,給這個 Socket 系結一個 IP 地址和埠,系結這兩個的目的是什么?

  • 系結埠的目的:當內核收到 TCP 報文,通過 TCP 頭里面的埠號,來找到我們的應用程式,然后把資料傳遞給我們,
  • 系結 IP 地址的目的:一臺機器是可以有多個網卡的,每個網卡都有對應的 IP 地址,當系結一個網卡時,內核在收到該網卡上的包,才會發給我們;

系結完 IP 地址和埠后,就可以呼叫 listen() 函式進行監聽,此時對應 TCP 狀態圖中的 listen,如果我們要判定服務器中一個網路程式有沒有啟動,可以通過 netstat 命令查看對應的埠號是否有被監聽,

服務端進入了監聽狀態后,通過呼叫 accept() 函式,來從內核獲取客戶端的連接,如果沒有客戶端連接,則會阻塞等待客戶端連接的到來,

那客戶端是怎么發起連接的呢?客戶端在創建好 Socket 后,呼叫 connect() 函式發起連接,該函式的引數要指明服務端的 IP 地址和埠號,然后萬眾期待的 TCP 三次握手就開始了,

在 TCP 連接的程序中,服務器的內核實際上為每個 Socket 維護了兩個佇列:

  • 一個是還沒完全建立連接的佇列,稱為 TCP 半連接佇列,這個佇列都是沒有完成三次握手的連接,此時服務端處于 syn_rcvd 的狀態;
  • 一個是一件建立連接的佇列,稱為 TCP 全連接佇列,這個佇列都是完成了三次握手的連接,此時服務端處于 established 狀態;

當 TCP 全連接佇列不為空后,服務端的 accept() 函式,就會從內核中的 TCP 全連接佇列里拿出一個已經完成連接的 Socket 回傳應用程式,后續資料傳輸都用這個 Socket,

注意,監聽的 Socket 和真正用來傳資料的 Socket 是兩個:

  • 一個叫作監聽 Socket
  • 一個叫作已連接 Socket

連接建立后,客戶端和服務端就開始相互傳輸資料了,雙方都可以通過 read()write() 函式來讀寫資料,

至此, TCP 協議的 Socket 程式的呼叫程序就結束了,整個程序如下圖:

看到這,不知道你有沒有覺得讀寫 Socket 的方式,好像讀寫檔案一樣,

是的,基于 Linux 一切皆檔案的理念,在內核中 Socket 也是以「檔案」的形式存在的,也是有對應的檔案描述符,

PS : 下面會說到內核里的資料結構,不感興趣的可以跳過這一部分,不會對后續的內容有影響,

檔案描述符的作用是什么?每一個行程都有一個資料結構 task_struct,該結構體里有一個指向「檔案描述符陣列」的成員指標,該陣列里列出這個行程打開的所有檔案的檔案描述符,陣列的下標是檔案描述符,是一個整數,而陣列的內容是一個指標,指向內核中所有打開的檔案的串列,也就是說內核可以通過檔案描述符找到對應打開的檔案,

然后每個檔案都有一個 inode,Socket 檔案的 inode 指向了內核中的 Socket 結構,在這個結構體里有兩個佇列,分別是發送佇列接收佇列,這個兩個佇列里面保存的是一個個 struct sk_buff,用鏈表的組織形式串起來,

sk_buff 可以表示各個層的資料包,在應用層資料包叫 data,在 TCP 層我們稱為 segment,在 IP 層我們叫 packet,在資料鏈路層稱為 frame,

你可能會好奇,為什么全部資料包只用一個結構體來描述呢?協議堆疊采用的是分層結構,上層向下層傳遞資料時需要增加包頭,下層向上層資料時又需要去掉包頭,如果每一層都用一個結構體,那在層之間傳遞資料的時候,就要發生多次拷貝,這將大大降低 CPU 效率,

于是,為了在層級之間傳遞資料時,不發生拷貝,只用 sk_buff 一個結構體來描述所有的網路包,那它是如何做到的呢?是通過調整 sk_buff 中 data 的指標,比如:

  • 當接收報文時,從網卡驅動開始,通過協議堆疊層層往上傳送資料報,通過增加 skb->data 的值,來逐步剝離協議首部,
  • 當要發送報文時,創建 sk_buff 結構體,資料快取區的頭部預留足夠的空間,用來填充各層首部,在經過各下層協議時,通過減少 skb->data 的值來增加協議首部,

你可以從下面這張圖看到,當發送報文時,data 指標的移動程序,


如何服務更多的用戶?

前面提到的 TCP Socket 呼叫流程是最簡單、最基本的,它基本只能一對一通信,因為使用的是同步阻塞的方式,當服務端在還沒處理完一個客戶端的網路 I/O 時,或者 讀寫操作發生阻塞時,其他客戶端是無法與服務端連接的,

可如果我們服務器只能服務一個客戶,那這樣就太浪費資源了,于是我們要改進這個網路 I/O 模型,以支持更多的客戶端,

在改進網路 I/O 模型前,我先來提一個問題,你知道服務器單機理論最大能連接多少個客戶端?

相信你知道 TCP 連接是由四元組唯一確認的,這個四元組就是:本機IP, 本機埠, 對端IP, 對端埠

服務器作為服務方,通常會在本地固定監聽一個埠,等待客戶端的連接,因此服務器的本地 IP 和埠是固定的,于是對于服務端 TCP 連接的四元組只有對端 IP 和埠是會變化的,所以最大 TCP 連接數 = 客戶端 IP 數×客戶端埠數

對于 IPv4,客戶端的 IP 數最多為 2 的 32 次方,客戶端的埠數最多為 2 的 16 次方,也就是服務端單機最大 TCP 連接數約為 2 的 48 次方

這個理論值相當“豐滿”,但是服務器肯定承載不了那么大的連接數,主要會受兩個方面的限制:

  • 檔案描述符,Socket 實際上是一個檔案,也就會對應一個檔案描述符,在 Linux 下,單個行程打開的檔案描述符數是有限制的,沒有經過修改的值一般都是 1024,不過我們可以通過 ulimit 增大檔案描述符的數目;
  • 系統記憶體,每個 TCP 連接在內核中都有對應的資料結構,意味著每個連接都是會占用一定記憶體的;

那如果服務器的記憶體只有 2 GB,網卡是千兆的,能支持并發 1 萬請求嗎?

并發 1 萬請求,也就是經典的 C10K 問題 ,C 是 Client 單詞首字母縮寫,C10K 就是單機同時處理 1 萬個請求的問題,

從硬體資源角度看,對于 2GB 記憶體千兆網卡的服務器,如果每個請求處理占用不到 200KB 的記憶體和 100Kbit 的網路帶寬就可以滿足并發 1 萬個請求,

不過,要想真正實作 C10K 的服務器,要考慮的地方在于服務器的網路 I/O 模型,效率低的模型,會加重系統開銷,從而會離 C10K 的目標越來越遠,


多行程模型

基于最原始的阻塞網路 I/O, 如果服務器要支持多個客戶端,其中比較傳統的方式,就是使用多行程模型,也就是為每個客戶端分配一個行程來處理請求,

服務器的主行程負責監聽客戶的連接,一旦與客戶端連接完成,accept() 函式就會回傳一個「已連接 Socket」,這時就通過 fork() 函式創建一個子行程,實際上就把父行程所有相關的東西都復制一份,包括檔案描述符、記憶體地址空間、程式計數器、執行的代碼等,

這兩個行程剛復制完的時候,幾乎一摸一樣,不過,會根據回傳值來區分是父行程還是子行程,如果回傳值是 0,則是子行程;如果回傳值是其他的整數,就是父行程,

正因為子行程會復制父行程的檔案描述符,于是就可以直接使用「已連接 Socket 」和客戶端通信了,

可以發現,子行程不需要關心「監聽 Socket」,只需要關心「已連接 Socket」;父行程則相反,將客戶服務交給子行程來處理,因此父行程不需要關心「已連接 Socket」,只需要關心「監聽 Socket」,

下面這張圖描述了從連接請求到連接建立,父行程創建生子行程為客戶服務,

另外,當「子行程」退出時,實際上內核里還會保留該行程的一些資訊,也是會占用記憶體的,如果不做好“回收”作業,就會變成僵尸行程,隨著僵尸行程越多,會慢慢耗盡我們的系統資源,

因此,父行程要“善后”好自己的孩子,怎么善后呢?那么有兩種方式可以在子行程退出后回收資源,分別是呼叫 wait()waitpid() 函式,

這種用多個行程來應付多個客戶端的方式,在應對 100 個客戶端還是可行的,但是當客戶端數量高達一萬時,肯定扛不住的,因為每產生一個行程,必會占據一定的系統資源,而且行程間背景關系切換的“包袱”是很重的,性能會大打折扣,

行程的背景關系切換不僅包含了虛擬記憶體、堆疊、全域變數等用戶空間的資源,還包括了內核堆疊、暫存器等內核空間的資源,


多執行緒模型

既然行程間背景關系切換的“包袱”很重,那我們就搞個比較輕量級的模型來應對多用戶的請求 —— 多執行緒模型

執行緒是運行在行程中的一個“邏輯流”,單行程中可以運行多個執行緒,同行程里的執行緒可以共享行程的部分資源的,比如檔案描述符串列、行程空間、代碼、全域資料、堆、共享庫等,這些共享些資源在背景關系切換時是不需要切換,而只需要切換執行緒的私有資料、暫存器等不共享的資料,因此同一個行程下的執行緒背景關系切換的開銷要比行程小得多,

當服務器與客戶端 TCP 完成連接后,通過 pthread_create() 函式創建執行緒,然后將「已連接 Socket」的檔案描述符傳遞給執行緒函式,接著在執行緒里和客戶端進行通信,從而達到并發處理的目的,

如果每來一個連接就創建一個執行緒,執行緒運行完后,還得作業系統還得銷毀執行緒,雖說執行緒切換的上寫文開銷不大,但是如果頻繁創建和銷毀執行緒,系統開銷也是不小的,

那么,我們可以使用執行緒池的方式來避免執行緒的頻繁創建和銷毀,所謂的執行緒池,就是提前創建若干個執行緒,這樣當由新連接建立時,將這個已連接的 Socket 放入到一個佇列里,然后執行緒池里的執行緒負責從佇列中取出已連接 Socket 行程處理,

需要注意的是,這個佇列是全域的,每個執行緒都會操作,為了避免多執行緒競爭,執行緒在操作這個佇列前要加鎖,

上面基于行程或者執行緒模型的,其實還是有問題的,新到來一個 TCP 連接,就需要分配一個行程或者執行緒,那么如果要達到 C10K,意味著要一臺機器維護 1 萬個連接,相當于要維護 1 萬個行程/執行緒,作業系統就算死扛也是扛不住的,


I/O 多路復用

既然為每個請求分配一個行程/執行緒的方式不合適,那有沒有可能只使用一個行程來維護多個 Socket 呢?答案是有的,那就是 I/O 多路復用技術,

一個行程雖然任一時刻只能處理一個請求,但是處理每個請求的事件時,耗時控制在 1 毫秒以內,這樣 1 秒內就可以處理上千個請求,把時間拉長來看,多個請求復用了一個行程,這就是多路復用,這種思想很類似一個 CPU 并發多個行程,所以也叫做時分多路復用,

我們熟悉的 select/poll/epoll 內核提供給用戶態的多路復用系統呼叫,行程可以通過一個系統呼叫函式從內核中獲取多個事件

select/poll/epoll 是如何獲取網路事件的呢?在獲取事件時,先把所有連接(檔案描述符)傳給內核,再由內核回傳產生了事件的連接,然后在用戶態中再處理這些連接對應的請求即可,

select/poll/epoll 這是三個多路復用介面,都能實作 C10K 嗎?接下來,我們分別說說它們,


select/poll

select 實作多路復用的方式是,將已連接的 Socket 都放到一個檔案描述符集合,然后呼叫 select 函式將檔案描述符集合拷貝到內核里,讓內核來檢查是否有網路事件產生,檢查的方式很粗暴,就是通過遍歷檔案描述符集合的方式,當檢查到有事件產生后,將此 Socket 標記為可讀或可寫, 接著再把整個檔案描述符集合拷貝回用戶態里,然后用戶態還需要再通過遍歷的方法找到可讀或可寫的 Socket,然后再對其處理,

所以,對于 select 這種方式,需要進行 2 次「遍歷」檔案描述符集合,一次是在內核態里,一個次是在用戶態里 ,而且還會發生 2 次「拷貝」檔案描述符集合,先從用戶空間傳入內核空間,由內核修改后,再傳出到用戶空間中,

select 使用固定長度的 BitsMap,表示檔案描述符集合,而且所支持的檔案描述符的個數是有限制的,在 Linux 系統中,由內核中的 FD_SETSIZE 限制, 默認最大值為 1024,只能監聽 0~1023 的檔案描述符,

poll 不再用 BitsMap 來存盤所關注的檔案描述符,取而代之用動態陣列,以鏈表形式來組織,突破了 select 的檔案描述符個數限制,當然還會受到系統檔案描述符限制,

但是 poll 和 select 并沒有太大的本質區別,都是使用「線性結構」存盤行程關注的 Socket 集合,因此都需要遍歷檔案描述符集合來找到可讀或可寫的 Socket,時間復雜度為 O(n),而且也需要在用戶態與內核態之間拷貝檔案描述符集合,這種方式隨著并發數上來,性能的損耗會呈指數級增長,


epoll

epoll 通過兩個方面,很好解決了 select/poll 的問題,

第一點,epoll 在內核里使用紅黑樹來跟蹤行程所有待檢測的檔案描述字,把需要監控的 socket 通過 epoll_ctl() 函式加入內核中的紅黑樹里,紅黑樹是個高效的資料結構,增刪查一般時間復雜度是 O(logn),通過對這棵黑紅樹進行操作,這樣就不需要像 select/poll 每次操作時都傳入整個 socket 集合,只需要傳入一個待檢測的 socket,減少了內核和用戶空間大量的資料拷貝和記憶體分配,

第二點, epoll 使用事件驅動的機制,內核里維護了一個鏈表來記錄就緒事件,當某個 socket 有事件發生時,通過回呼函式內核會將其加入到這個就緒事件串列中,當用戶呼叫 epoll_wait() 函式時,只會回傳有事件發生的檔案描述符的個數,不需要像 select/poll 那樣輪詢掃描整個 socket 集合,大大提高了檢測的效率,

從下圖你可以看到 epoll 相關的介面作用:

epoll 的方式即使監聽的 Socket 數量越多的時候,效率不會大幅度降低,能夠同時監聽的 Socket 的數目也非常的多了,上限就為系統定義的行程打開的最大檔案描述符個數,因而,epoll 被稱為解決 C10K 問題的利器

插個題外話,網上文章不少說,epoll_wait 回傳時,對于就緒的事件,epoll使用的是共享記憶體的方式,即用戶態和內核態都指向了就緒鏈表,所以就避免了記憶體拷貝消耗,

這是錯的!看過 epoll 內核原始碼的都知道,壓根就沒有使用共享記憶體這個玩意,你可以從下面這份代碼看到, epoll_wait 實作的內核代碼中呼叫了 __put_user 函式,這個函式就是將資料從內核拷貝到用戶空間,

好了,這個題外話就說到這了,我們繼續!

epoll 支持兩種事件觸發模式,分別是邊緣觸發(edge-triggered,ET水平觸發(level-triggered,LT

這兩個術語還挺抽象的,其實它們的區別還是很好理解的,

  • 使用邊緣觸發模式時,當被監控的 Socket 描述符上有可讀事件發生時,服務器端只會從 epoll_wait 中蘇醒一次,即使行程沒有呼叫 read 函式從內核讀取資料,也依然只蘇醒一次,因此我們程式要保證一次性將內核緩沖區的資料讀取完;
  • 使用水平觸發模式時,當被監控的 Socket 上有可讀事件發生時,服務器端不斷地從 epoll_wait 中蘇醒,直到內核緩沖區資料被 read 函式讀完才結束,目的是告訴我們有資料需要讀取;

舉個例子,你的快遞被放到了一個快遞箱里,如果快遞箱只會通過短信通知你一次,即使你一直沒有去取,它也不會再發送第二條短信提醒你,這個方式就是邊緣觸發;如果快遞箱發現你的快遞沒有被取出,它就會不停地發短信通知你,直到你取出了快遞,它才消停,這個就是水平觸發的方式,

這就是兩者的區別,水平觸發的意思是只要滿足事件的條件,比如內核中有資料需要讀,就一直不斷地把這個事件傳遞給用戶;而邊緣觸發的意思是只有第一次滿足條件的時候才觸發,之后就不會再傳遞同樣的事件了,

如果使用水平觸發模式,當內核通知檔案描述符可讀寫時,接下來還可以繼續去檢測它的狀態,看它是否依然可讀或可寫,所以在收到通知后,沒必要一次執行盡可能多的讀寫操作,

如果使用邊緣觸發模式,I/O 事件發生時只會通知一次,而且我們不知道到底能讀寫多少資料,所以在收到通知后應盡可能地讀寫資料,以免錯失讀寫的機會,因此,我們會回圈從檔案描述符讀寫資料,那么如果檔案描述符是阻塞的,沒有資料可讀寫時,行程會阻塞在讀寫函式那里,程式就沒辦法繼續往下執行,所以,邊緣觸發模式一般和非阻塞 I/O 搭配使用,程式會一直執行 I/O 操作,直到系統呼叫(如 readwrite)回傳錯誤,錯誤型別為 EAGAINEWOULDBLOCK

一般來說,邊緣觸發的效率比水平觸發的效率要高,因為邊緣觸發可以減少 epoll_wait 的系統呼叫次數,系統呼叫也是有一定的開銷的的,畢竟也存在背景關系的切換,

select/poll 只有水平觸發模式,epoll 默認的觸發模式是水平觸發,但是可以根據應用場景設定為邊緣觸發模式,

另外,使用 I/O 多路復用時,最好搭配非阻塞 I/O 一起使用,Linux 手冊關于 select 的內容中有如下說明:

Under Linux, select() may report a socket file descriptor as “ready for reading”, while nevertheless a subsequent read blocks. This could for example happen when data has arrived but upon examination has wrong checksum and is discarded. There may be other circumstances in which a file descriptor is spuriously reported as ready. Thus it may be safer to use O_NONBLOCK on sockets that should not block.

我谷歌翻譯的結果:

在Linux下,select() 可能會將一個 socket 檔案描述符報告為 “準備讀取”,而后續的讀取塊卻沒有,例如,當資料已經到達,但經檢查后發現有錯誤的校驗和而被丟棄時,就會發生這種情況,也有可能在其他情況下,檔案描述符被錯誤地報告為就緒,因此,在不應該阻塞的 socket 上使用 O_NONBLOCK 可能更安全,

簡單點理解,就是多路復用 API 回傳的事件并不一定可讀寫的,如果使用阻塞 I/O, 那么在呼叫 read/write 時則會發生程式阻塞,因此最好搭配非阻塞 I/O,以便應對極少數的特殊情況,


總結

最基礎的 TCP 的 Socket 編程,它是阻塞 I/O 模型,基本上只能一對一通信,那為了服務更多的客戶端,我們需要改進網路 I/O 模型,

比較傳統的方式是使用多行程/執行緒模型,每來一個客戶端連接,就分配一個行程/執行緒,然后后續的讀寫都在對應的行程/執行緒,這種方式處理 100 個客戶端沒問題,但是當客戶端增大到 10000 個時,10000 個行程/執行緒的調度、背景關系切換以及它們占用的記憶體,都會成為瓶頸,

為了解決上面這個問題,就出現了 I/O 的多路復用,可以只在一個行程里處理多個檔案的 I/O,Linux 下有三種提供 I/O 多路復用的 API,分別是: select、poll、epoll,

select 和 poll 并沒有本質區別,它們內部都是使用「線性結構」來存盤行程關注的 Socket 集合,

在使用的時候,首先需要把關注的 Socket 集合通過 select/poll 系統呼叫從用戶態拷貝到內核態,然后由內核檢測事件,當有網路事件產生時,內核需要遍歷行程關注 Socket 集合,找到對應的 Socket,并設定其狀態為可讀/可寫,然后把整個 Socket 集合從內核態拷貝到用戶態,用戶態還要繼續遍歷整個 Socket 集合找到可讀/可寫的 Socket,然后對其處理,

很明顯發現,select 和 poll 的缺陷在于,當客戶端越多,也就是 Socket 集合越大,Socket 集合的遍歷和拷貝會帶來很大的開銷,因此也很難應對 C10K,

epoll 是解決 C10K 問題的利器,通過兩個方面解決了 select/poll 的問題,

  • epoll 在內核里使用「紅黑樹」來關注行程所有待檢測的 Socket,紅黑樹是個高效的資料結構,增刪查一般時間復雜度是 O(logn),通過對這棵黑紅樹的管理,不需要像 select/poll 在每次操作時都傳入整個 Socket 集合,減少了內核和用戶空間大量的資料拷貝和記憶體分配,
  • epoll 使用事件驅動的機制,內核里維護了一個「鏈表」來記錄就緒事件,只將有事件發生的 Socket 集合傳遞給應用程式,不需要像 select/poll 那樣輪詢掃描整個集合(包含有和無事件的 Socket ),大大提高了檢測的效率,

而且,epoll 支持邊緣觸發和水平觸發的方式,而 select/poll 只支持水平觸發,一般而言,邊緣觸發的方式會比水平觸發的效率高,


參考資料
  1. https://www.zhihu.com/question/39792257
  2. https://journey-c.github.io/io-multiplexing/#25-io-multiplexing
  3. https://panqiincs.me/2015/08/01/io-multiplexing-with-epoll/

推薦閱讀

圖解 TCP 三次握手和四次揮手

圖解 TCP 內核引數

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/275733.html

標籤:AI

上一篇:中國聯通6G白皮書筆記

下一篇:TensorFlow Probability 聯合分布變分推斷工具,估計權重的貝葉斯可信區間更簡單

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more