主頁 > 後端開發 > 提升性能的利器:深入決議SectionReader

提升性能的利器:深入決議SectionReader

2023-07-03 07:38:51 後端開發

一. 簡介

本文將介紹 Go 語言中的 SectionReader,包括 SectionReader的基本使用方法、實作原理、使用注意事項,從而能夠在合適的場景下,更好得使用SectionReader型別,提升程式的性能,

二. 問題引入

這里我們需要實作一個基本的HTTP檔案服務器功能,可以處理客戶端的HTTP請求來讀取指定檔案,并根據請求的Range頭部欄位回傳檔案的部分資料或整個檔案資料,

這里一個簡單的思路,可以先把整個檔案的資料加載到記憶體中,然后再根據請求指定的范圍,截取對應的資料回傳回去即可,下面提供一個代碼示例:

func serveFile(w http.ResponseWriter, r *http.Request, filePath string) {
    // 打開檔案
    file, _ := os.Open(filePath)
    defer file.Close()

    // 讀取整個檔案資料
    fileData, err := ioutil.ReadAll(file)
    if err != nil {
        // 錯誤處理
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    // 根據Range頭部欄位決議請求的范圍
    rangeHeader := r.Header.Get("Range")
    ranges, err := parseRangeHeader(rangeHeader)
    if err != nil {
        // 錯誤處理
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    // 處理每個范圍并回傳資料
    for _, rng := range ranges {
        start := rng.Start
        end := rng.End
        // 從檔案資料中提取范圍的位元組資料
        rangeData := fileData[start : end+1]

        // 將范圍資料寫入回應
        w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, end, fileInfo.Size()))
        w.Header().Set("Content-Length", strconv.Itoa(len(rangeData)))
        w.WriteHeader(http.StatusPartialContent)
        w.Write(rangeData)
    }
}

type Range struct {
    Start int
    End   int
}

// 決議HTTP Range請求頭
func parseRangeHeader(rangeHeader string) ([]Range, error){}

上述的代碼實作比較簡單,首先,函式打開filePath指定的檔案,使用ioutil.ReadAll函式讀取整個檔案的資料到fileData中,接下來,從HTTP請求頭中Range頭部欄位中獲取范圍資訊,獲取每個范圍請求的起始和終止位置,接著,函式遍歷每一個范圍資訊,提取檔案資料fileData 中對應范圍的位元組資料到rangeData中,然后將資料回傳回去,基于此,簡單實作了一個支持范圍請求的HTTP檔案服務器,

但是當前實作其實存在一個問題,即在每次請求都會將整個檔案加載到記憶體中,即使用戶只需要讀取其中一小部分資料,這種處理方式會給記憶體帶來非常大的壓力,假如被請求檔案的大小是100M,一個32G記憶體的機器,此時最多只能支持320個并發請求,但是用戶每次請求可能只是讀取檔案的一小部分資料,比如1M,此時將整個檔案加載到記憶體中,往往是一種資源的浪費,同時從磁盤中讀取全部資料到記憶體中,此時性能也較低,

那能不能在處理請求時,HTTP檔案服務器只讀取請求的那部分資料,而不是加載整個檔案的內容,go基礎庫有對應型別的支持嗎?

其實還真有,Go語言中其實存在一個SectionReader的型別,它可以從一個給定的資料源中讀取資料的特定片段,而不是讀取整個資料源,這個型別在這個場景下使用非常合適,

下面我們先仔細介紹下SectionReader的基本使用方式,然后將其作用到上面檔案服務器的實作當中,

三. 基本使用

3.1 基本定義

SectionReader型別的定義如下:

type SectionReader struct {
   r     ReaderAt
   base  int64
   off   int64
   limit int64
}

SectionReader包含了四個欄位:

  • r:一個實作了ReaderAt介面的物件,它是資料源,
  • base: 資料源的起始位置,通過設定base欄位,可以調整資料源的起始位置,
  • off:讀取的起始位置,表示從資料源的哪個偏移量開始讀取資料,初始化時一般與base保持一致,
  • limit:資料讀取的結束位置,表示讀取到哪里結束,

同時還提供了一個構造器方法,用于創建一個SectionReader實體,定義如下:

func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader {
   // ... 忽略一些驗證邏輯
   // remaining 代表資料讀取的結束位置,為 base(偏移量) + n(讀取位元組數)
   remaining = n + off
   return &SectionReader{r, off, off, remaining}
}

NewSectionReader接收三個引數,r 代表實作了ReadAt介面的資料源,off表示起始位置的偏移量,也就是要從哪里開始讀取資料,n代表要讀取的位元組數,通過NewSectionReader函式,可以很方便得創建出SectionReader物件,然后讀取特定范圍的資料,

3.2 使用方式

SectionReader 能夠像io.Reader一樣讀取資料,唯一區別是會被限定在指定范圍內,只會回傳特定范圍的資料,

下面通過一個例子來說明SectionReader的使用,代碼示例如下:

package main

import (
        "fmt"
        "io"
        "strings"
)

func main() {
        // 一個實作了 ReadAt 介面的資料源
        data := strings.NewReader("Hello,World!")

        // 創建 SectionReader,讀取范圍為索引 2 到 9 的位元組
        // off = 2, 代表從第二個位元組開始讀取; n = 7, 代表讀取7個位元組
        section := io.NewSectionReader(data, 2, 7)
        // 資料讀取緩沖區長度為5
        buffer := make([]byte, 5)
        for {
                // 不斷讀取資料,直到回傳io.EOF
                n, err := section.Read(buffer)
                if err != nil {
                        if err == io.EOF {
                                // 已經讀取到末尾,退出回圈
                                break
                        }
                        fmt.Println("Error:", err)
                        return
                }

                fmt.Printf("Read %d bytes: %s\n", n, buffer[:n])
        }
}

上述函式使用 io.NewSectionReader 創建了一個 SectionReader,指定了開始讀取偏移量為 2,讀取位元組數為 7,這意味著我們將從第三個位元組(索引 2)開始讀取,讀取 7 個位元組,

然后我們通過一個無限回圈,不斷呼叫Read方法讀取資料,直到讀取完所有的資料,函式運行結果如下,確實只讀取了范圍為索引 2 到 9 的位元組的內容:

Read 5 bytes: llo,W
Read 2 bytes: or

因此,如果我們只需要讀取資料源的某一部分資料,此時可以創建一個SectionReader實體,定義好資料讀取的偏移量和資料量之后,之后可以像普通的io.Reader那樣讀取資料,SectionReader確保只會讀取到指定范圍的資料,

3.3 使用例子

這里回到上面HTTP檔案服務器實作的例子,之前的實作存在一個問題,即每次請求都會讀取整個檔案的內容,這會代碼記憶體資源的浪費,性能低,回應時間比較長等問題,下面我們使用SectionReader 對其進行優化,實作如下:

func serveFile(w http.ResponseWriter, r *http.Request, filePath string) {
        // 打開檔案
        file, err := os.Open(filePath)
        if err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return
        }
        defer file.Close()

        // 獲取檔案資訊
        fileInfo, err := file.Stat()
        if err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return
        }

        // 根據Range頭部欄位決議請求的范圍
        rangeHeader := r.Header.Get("Range")
        ranges, err := parseRangeHeader(rangeHeader)
        if err != nil {
                http.Error(w, err.Error(), http.StatusBadRequest)
                return
        }

        // 處理每個范圍并回傳資料
        for _, rng := range ranges {
                start := rng.Start
                end := rng.End

                // 根據范圍創建SectionReader
                section := io.NewSectionReader(file, int64(start), int64(end-start+1))

                // 將范圍資料寫入回應
                w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, end, fileInfo.Size()))
                w.WriteHeader(http.StatusPartialContent)
                io.CopyN(w, section, section.Size())
        }
}

type Range struct {
        Start int
        End   int
}
// 決議HTTP Range請求頭
func parseRangeHeader(rangeHeader string) ([]Range, error) {}

在上述優化后的實作中,我們使用 io.NewSectionReader 創建了 SectionReader,它的范圍是根據請求頭中的范圍資訊計算得出的,然后,我們通過 io.CopyNSectionReader 中的資料直接拷貝到回應的 http.ResponseWriter 中,

上述兩個HTTP檔案服務器實作的區別,只在于讀取特定范圍資料方式,前一種方式是將整個檔案加載到記憶體中,再截取特定范圍的資料;而后者則是通過使用 SectionReader,我們避免了一次性讀取整個檔案資料,并且只讀取請求范圍內的資料,這種優化能夠更高效地處理大檔案或處理大量并發請求的場景,節省了記憶體和處理時間,

四. 實作原理

4.1 設計初衷

SectionReader的設計初衷,在于提供一種簡潔,靈活的方式來讀取資料源的特定部分,

4.2 基本原理

SectionReader 結構體中offbaselimit欄位是實作只讀取資料源特定部分資料功能的重要變數,

type SectionReader struct {
   r     ReaderAt
   base  int64
   off   int64
   limit int64
}

由于SectionReader需要保證只讀取特定范圍的資料,故需要保存開始位置和結束位置的值,這里是通過baselimit這兩個欄位來實作的,base記錄了資料讀取的開始位置,limit記錄了資料讀取的結束位置,

通過設定baselimit兩個欄位的值,限制了能夠被讀取資料的范圍,之后需要開始讀取資料,有可能這部分待讀取的資料不會被一次性讀完,此時便需要一個欄位來說明接下來要從哪一個位元組繼續讀取下去,因此SectionReader也設定了off欄位的值,這個代表著下一個帶讀取資料的位置,

在使用SectionReader讀取資料的程序中,通過baselimit限制了讀取資料的范圍,off則不斷修改,指向下一個帶讀取的位元組,

4.3 代碼實作

4.3.1 Read方法說明

func (s *SectionReader) Read(p []byte) (n int, err error) {
    // s.off: 將被讀取資料的下標
    // s.limit: 指定讀取范圍的最后一個位元組,這里應該保證s.base <= s.off
   if s.off >= s.limit {
      return 0, EOF
   }
   // s.limit - s.off: 還剩下多少資料未被讀取
   if max := s.limit - s.off; int64(len(p)) > max {
      p = p[0:max]
   }
   // 呼叫 ReadAt 方法讀取資料
   n, err = s.r.ReadAt(p, s.off)
   // 指向下一個待被讀取的位元組
   s.off += int64(n)
   return
}

SectionReader實作了Read 方法,通過該方法能夠實作指定范圍資料的讀取,在內部實作中,通過兩個限制來保證只會讀取到指定范圍的資料,具體限制如下:

  • 通過保證 off 不大于 limit 欄位的值,保證不會讀取超過指定范圍的資料
  • 在呼叫ReadAt方法時,保證傳入切片長度不大于剩余可讀資料長度

通過這兩個限制,保證了用戶只要設定好了資料開始讀取偏移量 base 和 資料讀取結束偏移量 limit欄位值,Read方法便只會讀取這個范圍的資料,

4.3.2 ReadAt 方法說明

func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err error) {
    // off: 引數指定了偏移位元組數,為一個相對數值
    // s.limit - s.base >= off: 保證不會越界
   if off < 0 || off >= s.limit-s.base {
      return 0, EOF
   }
   // off + base: 獲取絕對的偏移量
   off += s.base
   // 確保傳入位元組陣列長度 不超過 剩余讀取資料范圍
   if max := s.limit - off; int64(len(p)) > max {
      p = p[0:max]
      // 呼叫ReadAt 方法讀取資料
      n, err = s.r.ReadAt(p, off)
      if err == nil {
         err = EOF
      }
      return n, err
   }
   return s.r.ReadAt(p, off)
}

SectionReader還提供了ReadAt方法,能夠指定偏移量處實作資料讀取,它根據傳入的偏移量off欄位的值,計算出實際的偏移量,并呼叫底層源的ReadAt方法進行讀取操作,在這個程序中,也保證了讀取資料范圍不會超過baselimit欄位指定的資料范圍,

這個方法提供了一種靈活的方式,能夠在限定的資料范圍內,隨意指定偏移量來讀取資料,不過需要注意的是,該方法并不會影響實體中off欄位的值,

4.3.3 Seek 方法說明

func (s *SectionReader) Seek(offset int64, whence int) (int64, error) {
   switch whence {
   default:
      return 0, errWhence
   case SeekStart:
      // s.off = s.base + offset
      offset += s.base
   case SeekCurrent:
      // s.off = s.off + offset
      offset += s.off
   case SeekEnd:
      // s.off = s.limit + offset
      offset += s.limit
   }
   // 檢查
   if offset < s.base {
      return 0, errOffset
   }
   s.off = offset
   return offset - s.base, nil
}

SectionReader也提供了Seek方法,給其提供了隨機訪問和靈活讀取資料的能力,舉個例子,假如已經呼叫Read方法讀取了一部分資料,但是想要重新讀取該資料,此時便可以使Seek方法將off欄位設定回之前的位置,然后再次呼叫Read方法進行讀取,

五. 使用注意事項

5.1 注意off值在base和limit之間

當使用 SectionReader 創建實體時,確保 off 值在 baselimit 之間是至關重要的,保證 off 值在 baselimit 之間的好處是確保讀取操作在有效的資料范圍內進行,避免讀取錯誤或超出范圍的訪問,如果 off 值小于 base 或大于等于 limit,讀取操作可能會導致錯誤或回傳 EOF,

一個良好的實踐方式是使用 NewSectionReader 函式來創建 SectionReader 實體,NewSectionReader 函式會檢查 off 值是否在有效范圍內,并自動調整 off 值,以確保它在 baselimit 之間,

5.2 及時關閉底層資料源

當使用SectionReader時,如果沒有及時關閉底層資料源可能會導致資源泄露,這些資源在程式執行期間將一直保持打開狀態,直到程式終止,在處理大量請求或長時間運行的情況下,可能會耗盡系統的資源,

下面是一個示例,展示了沒有關閉SectionReader底層資料源可能引發的問題:

func main() {
    file, err := os.Open("data.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    section := io.NewSectionReader(file, 10, 20)

    buffer := make([]byte, 10)
    _, err = section.Read(buffer)
    if err != nil {
        log.Fatal(err)
    }

    // 沒有關閉底層資料源,可能導致資源泄露或其他問題
}

在上述示例中,底層資料源是一個檔案,在程式結束時,沒有顯式呼叫file.Close()來關閉檔案句柄,這將導致檔案資源一直保持打開狀態,直到程式終止,這可能導致其他行程無法訪問該檔案或其他與檔案相關的問題,

因此,在使用SectionReader時,要注意及時關閉底層資料源,以確保資源的正確管理和避免潛在的問題,

六. 總結

本文主要對SectionReader進行了介紹,文章首先從一個基本HTTP檔案服務器的功能實作出發,解釋了該實作存在記憶體資源浪費,并發性能低等問題,從而引出了SectionReader

接下來介紹了SectionReader的基本定義,以及其基本使用方法,最后使用SectionReader對上述HTTP檔案服務器進行優化,接著還詳細講述了SectionReader的實作原理,從而能夠更好得理解和使用SectionReader

最后,講解了SectionReader的使用注意事項,如需要及時關閉底層資料源等,基于此完成了SectionReader的介紹,

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

標籤:其他

上一篇:初識識別符號

下一篇:返回列表

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

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • 提升性能的利器:深入決議SectionReader

    # 一. 簡介 本文將介紹 Go 語言中的 `SectionReader`,包括 `SectionReader`的基本使用方法、實作原理、使用注意事項。從而能夠在合適的場景下,更好得使用`SectionReader`型別,提升程式的性能。 # 二. 問題引入 這里我們需要實作一個基本的HTTP檔案服 ......

    uj5u.com 2023-07-03 07:38:51 more
  • 初識識別符號

    關鍵字 abstractassertbooleanbreakbyte case catch char class const continue default do double else enum extends final finally float for goto if implementi ......

    uj5u.com 2023-07-03 07:38:47 more
  • [滲透測驗]—7.4 逆向工程和二進制破解技術

    在本章節中,我們將深入學習逆向工程和二進制破解技術。我們將盡量詳細、通俗易懂地講解,并提供盡可能多的實體。 ## 1.1 逆向工程概述 逆向工程是指從軟體的二進制檔案中提取資訊,以了解其作業原理和設計思路的程序。逆向工程的主要目的是對軟體進行分析、除錯、修改等操作,以實作特定目的(如安全分析、病毒分 ......

    uj5u.com 2023-07-03 07:38:41 more
  • Java雜記————object.getClass()和object.class以及Java中的t

    不說廢話,直接上干貨: (注意大小寫:object為物件,Object為類) 1,object.getClass()它是Object類的實體方法,回傳一個物件運行時的類的Class物件,換句話說,它回傳的是物件具體型別的類物件。 2,Object.class 這是java語言的一種語法糖,用來回傳一 ......

    uj5u.com 2023-07-03 07:38:33 more
  • 基于嵌入式Tomcat的War包啟動器

    # 前言 最近針對java專案的部署方式進行整理,jenkins/tomcat/windows工具/linux腳本/web部署平臺等等 發現war包通過tomcat部署比較繁瑣,等待時間長,配置規則復雜對于小白很不友好,也難以接入到自定義的部署工具/平臺中 之前開發的Jar包部署平臺是servlet ......

    uj5u.com 2023-07-03 07:38:28 more
  • 【numpy基礎】--陣列索引

    陣列索引是指在`numpy`陣列中參考特定元素的方法。`numpy`的陣列索引又稱為`fancy indexing`,比其他編程語言的索引強大很多。 # 1. 選取資料 numpy的索引除了像其他語言一樣選擇一個元素,還可以間隔著選取多個元素,也可以用任意的順序選取元素。 比如一維陣列: ```py ......

    uj5u.com 2023-07-03 07:37:24 more
  • urllib+BeautifulSoup爬取并決議2345天氣王歷史天氣資料

    urllib+BeautifulSoup爬取并決議2345天氣王歷史天氣資料 網址:[東城歷史天氣查詢_歷史天氣預報查詢_2345天氣預報](https://tianqi.2345.com/wea_history/71445.htm) ![image-20230702161423470](https ......

    uj5u.com 2023-07-03 07:31:55 more
  • JavaCV的攝像頭實戰之十二:性別檢測

    ### 歡迎訪問我的GitHub > 這里分類和匯總了欣宸的全部原創(含配套原始碼):[https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) ### 本篇概覽 - 本文是《JavaCV的攝像頭實戰》系列的 ......

    uj5u.com 2023-07-01 07:45:34 more
  • [滲透測驗]—7.2 社會工程學攻擊技術

    在本章節中,我們將學習社會工程學攻擊技術,包括釣魚、身份欺詐等。我們會盡量詳細、通俗易懂地講解,并提供盡可能多的實體。 ### 1.1 社會工程學概述 社會工程學是一種利用人際交往中的心理因素來獲取資訊、權限或其他目標的手段。與技術性攻擊手段相比,社會工程學更側重于利用人的弱點,如信任、懶惰、貪婪等 ......

    uj5u.com 2023-07-01 07:44:29 more
  • C++面試八股文:什么是空指標/野指標/懸垂指標?

    某日二師兄參加XXX科技公司的C++工程師開發崗位第30面: > 面試官:什么是空指標? > > 二師兄:一般我們將等于`0`/`NULL`/`nullptr`的指標稱為空指標。空指標不能被解參考,但是可以對空指標取地址。 ```c++ int* p = nullptr; //空指標 *p = 42 ......

    uj5u.com 2023-07-01 07:44:24 more