<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    Go:Channel使用模式

    一顆小胡椒2022-07-20 11:05:42

    有幾種重要的channel模式需要理解,因為channel實現了Goroutine之間的通信。

    等待結果模式

    這是channel的基本使用模式,創建一個goroutine來執行任務,然后將執行結果通過channel通知到對應的其他Goroutine。

    func WaitForResult() {
        ch := make(chan string)
        go func() {
            time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
            ch <- "data"
            fmt.Println("child : sent signal")
        }()
        d := <-ch
        fmt.Println("parent : recv'd signal :", d)
        time.Sleep(time.Second)
        fmt.Println("--------------------")
    }
    

    這里使用不帶緩存的channel來接收數據,可以保證子goroutine發送的數據立刻被接收到。

    扇出/扇入模式

    這種模式是包含多個Goroutine向channel發送數據,要保證數據都能接收到。

    func FanOut() {
        children := 2000
        ch := make(chan string, children)
        for c := 0; c < children; c++ {
            go func(child int) {
                time.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond)
                ch <- "data"
                fmt.Println("child : sent signal :", child)
            }(c)
        }
        for children > 0 {
            d := <-ch
            children--
            fmt.Println(d)
            fmt.Println("parent : recv'd signal :", children)
        }
        time.Sleep(time.Second)
        fmt.Println("---------------")
    }
    

    這里我們創建了2000個goroutine來執行任務,為了保證Goroutine不會相互影響,采用帶緩存的channel來接收執行結果。主goroutine使用for循環來接收channel里面的數據。sleep模擬執行的任務。

    等待任務模式

    這種模式是子goroutine通過channel接收來自主goroutine發送的數據,也可以是執行任務的函數。

    func WaitForTask() {
        ch := make(chan string)
        go func() {
            d := <-ch
            fmt.Println("child : recv'd signal :", d)
        }()
        time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
        ch <- "data"
        fmt.Println("parent : sent signal")
        time.Sleep(time.Second)
        fmt.Println("---------------")
    }
    

    這里也是使用不帶緩存的channel,子goroutine等待channel發送數據,接收并執行任務。

    Goroutine池

    該模式還使用了等待任務模式,允許根據資源情況限制子goroutine的個數。

    func pooling() {
        ch := make(chan string)
        g := runtime.GOMAXPROCS(0)
        for c := 0; c < g; c++ {
            go func(child int) {
                for d := range ch {
                    fmt.Printf("child %d : recv'd signal : %s\n", child, d)
                }
                fmt.Printf("child %d : recv'd shutdown signal\n", child)
            }(c)
    }
        const work = 100
        for w := 0; w < work; w++ {
            ch <- "data"
            fmt.Println("parent : sent signal :", w)
        }
        close(ch)
        fmt.Println("parent : sent shutdown signal")
        time.Sleep(time.Second)
        fmt.Println("------------------")
    }
    

    這里我們創建了一組Goroutine來接收同一個channel發送來的數據。這里高效的原因是多個goroutine可以并行執行,注意不是并發。

    首先創建一個不帶緩沖的通道。使用無緩沖的通道是至關重要的,因為如果沒有信號級別的保證,就不能在發送時執行超時和取消。代碼的下一部分決定池將包含的子Goroutines的數量。

    g := runtime.GOMAXPROCS(0)
    

    該函數可以讀取機器cpu核數,也就是能并行執行代碼的cpu核數。如果參數大于0,直接返回的是并發數。

    使用for-range讀取channel中的數據可以節省代碼,當然也可以使用以下代碼來讀取channel數據:

    for c := 0; c < g; c++ {
        go func( child int) {
            for {     
               d, wd := <-ch     <-- CHANGED 
               if !wd {          <-- CHANGED
                  break          <-- CHANGED
               }
                fmt.Printf("child %d : recv'd signal : %s\n", child, d)
            }
            fmt.Printf("child %d : recv'd shutdown signal\n", child)
        }(c)
    }
    

    Drop模式

    該模式在寫入channel的數據量比較大的時候,超出緩沖的容量就選擇丟棄數據。例如當應用程序負載太大就可以丟棄一些請求。

    func Drop() {
        const cap = 100
        ch := make(chan string, cap)
        go func() {
            for p := range ch {
                fmt.Println("child : recv'd signal :", p)
            }
        }()
        const work = 2000
        for w := 0; w < work; w++ {
            select {
            case ch <- "data":
                fmt.Println("parent : sent signal :", w)
            default:
                fmt.Println("parent : dropped data :", w)
            }
        }
        close(ch)
        fmt.Println("parent : sent shutdown signal")
        time.Sleep(time.Second)
        fmt.Println("-----------------")
    }
    

    我們創建一個帶緩存的channel和一個Goroutine來接收任務。在緩沖區被填滿之前,Goroutine無法及時處理所有的工作。表示服務已滿負荷運行。

    在for循環里面使用select,是一個受阻塞的模塊,每個case代表一個channel操作,發送或接收。但是,這個select也使用了default關鍵字,它將select轉換為非阻塞調用。關鍵就在這里,如果channel緩沖區滿了,select就會執行default。在web服務里面,我們可以在default中返回500內部錯誤,或者將請求存起來。

    取消模式

    取消模式用于在執行一些IO操作的時候,可以選擇超時時間。你可以選擇取消操作,或者直接退出。

    func Cancellation() {
        duration := 150 * time.Millisecond
        ctx, cancel := context.WithTimeout(context.Background(), duration)
        defer cancel()
        ch := make(chan string, 1)
        go func() {
            time.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond)
            ch <- "data"
        }()
        select {
        case d := <-ch:
            fmt.Println("work complete", d)
        case <-ctx.Done():
            fmt.Println("work cancelled")
        }
        time.Sleep(time.Second)
        fmt.Println("-------------")
    }
    

    這里使用context創建超時上下文實例ctx,主Goroutine在select中通過ctx.Done讀取是否超時。這里使用defer調用cancel()防止內存溢出。

    在主goroutine中select等待ch通道數據或者超時,哪個先完成就執行哪個case。

    帶信號量的扇入/扇出

    這種模式可以隨時控制可執行的Goroutine數量。

    func FanOutSem() {
        children := 2000
        ch := make(chan string, children)
        g := runtime.GOMAXPROCS(0)
        sem := make(chan bool, g)
        for c := 0; c < children; c++ {
            go func(child int) {
                sem <- true
                {
                    t := time.Duration(rand.Intn(200)) * time.Millisecond
                    time.Sleep(t)
                    ch <- "data"
                    fmt.Println("child : sent signal :", child)
                }
                <-sem
            }(c)
        }
        for children > 0 {
            d := <-ch
            children--
            fmt.Println(d)
            fmt.Println("parent : recv'd signal :", children)
        }
        time.Sleep(time.Second)
        fmt.Println("-------------")
    }
    

    這里一開始創建了一個緩沖為2000的channel。和前面的扇入/扇出沒啥區別。另一個chennel sem也被創建了,在每個子goroutine內部使用,可以控制子Goroutine是否能夠寫入數據容量,緩沖區滿的話子goroutine就會阻塞。后面的for循環用于等待每個goroutine執行完成。

    重試超時模式

    這種模式在網絡服務中很實用,例如在連接數據庫的時候,發起ping操作可能會失敗,但是并不希望馬上退出,而是在一定時間內發起重試。

    func RetryTimeout(ctx context.Context, retryInterval time.Duration,
        check func(ctx context.Context) error) {
        for {
            fmt.Println("perform user check call")
            if err := check(ctx); err == nil {
                fmt.Println("work finished successfully")
                return
            }
            fmt.Println("check if timeout has expired")
            if ctx.Err() != nil {
                fmt.Println("time expired 1 :", ctx.Err())
                return
            }
            fmt.Printf("wait %s before trying again\n", retryInterval)
            t := time.NewTimer(retryInterval)
            select {
            case <-ctx.Done():
                fmt.Println("timed expired 2 :", ctx.Err())
                t.Stop()
                return
            case <-t.C:
                fmt.Println("retry again")
            }
        }
    }
    

    這里函數接收一個context指定超時時間,每次重試時間間隔,以及重試函數check,由函數調用者定義。

    該函數的核心是for無限循環,在循環內先檢查check函數是否執行完成,接著在select中判斷是否超時,以及定義重試計時器。

    channel取消模式

    可以創建一個單獨的channel用來實現取消的功能。

    func channelCancellation(stop <-chan struct{}) {
        ctx, cancel := context.WithCancel(context.Background())
        defer cancel()
        go func() {
            select {
            case <-stop:    
                cancel()
            case <-ctx.Done():
            }
        }()    
          
        func(ctx context.Context) error {
            req, err := http.NewRequestWithContext(
                ctx,
                http.MethodGet,
                "https://www.ardanlabs.com/blog/index.xml",
                nil,     
            )
            if err != nil {
                return err
            }
            _, err = http.DefaultClient.Do(req)
            if err != nil {
                return err     
            }
            return nil
        }(ctx)
    }
    

    該函數的關鍵在于創建一個新的goroutine并使用select來等待兩個channel發送的數據。第一個channel是一個空結構體類型,另一個是context。在接收到stop通道值時,就調用cancel函數,取消所有接收了對應context函數的執行。

    contextselect函數
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    函數簡介 云函數是騰訊云為企業和開發者們提供的無服務器執行環境,可以無需購買和管理服務器的情況下運行代碼。只需使用平臺支持的語言編寫核心代碼并設置代碼運行的條件,即可在騰訊云基礎設施上彈性、安全地運行代碼。SCF是實時文件處理和數據處理等場景下理想的計算平臺。服務端配置云函數基礎配置選擇自定義創建,地域自選,部署模式,代碼部署,運行環境Python3.6,其余默認即可。
    先看第二個LoopCrypto老規矩,先查殼:然后就可以看看java層啦:先在xml文件中找到文件的入口點就可以分析了:然后進入到入口點:就是用這個函數Decode.m2957a()先解密兩個字符串。
    脫敏前電話號碼,CONCAT(LEFT(mobilePhone,3),?身份證號碼脫敏sql:. 根據定義的策略類型,對數據進行脫敏,當然策略可以自定義。請添加微信wx153666購買授權,不白嫖從我做起!?測試證書會失效,請勿正式環境使用
    ByteCTF-WriteUp
    2021-10-19 06:38:36
    /files../路由發現了目錄穿越,在/var/lib/clickhouse/access/找到.sql文件,可以看到user_01用戶名密碼。
    Advantech iView 多個不同類型匿名 RCE 漏洞分享
    分析漏洞的本質是為了能讓我們從中學習漏洞挖掘者的思路以及挖掘到新的漏洞,而CodeQL就是一款可以將我們對漏洞的理解快速轉化為可實現的規則并挖掘漏洞的利器。根據網上的傳言Log4j2的RCE漏洞就是作者通過CodeQL挖掘出的。雖然如何挖掘的我們不得而知,但我們現在站在事后的角度再去想想,可以推測一下作者如何通過CodeQL挖掘到漏洞的,并嘗試基于作者的思路挖掘新漏洞。
    下半部分則基于模擬環境對《3GPP TS 33.501》中定義的相關安全服務進行詳細分析。5gc各模擬網元與模擬RAN 通過虛擬網橋進行數據交換。下文將基于UERANSIM+free5gc 模擬環境的報文、項目代碼、協議標準三位一體的對該注冊管理流程進行分析。
    動態防護技術
    2022-07-13 17:20:00
    動態防護技術是面向App運行過程的防護,一方面可以通過App動態加固技術來實現,比如程序數據加解密保護、進程防動態調試保護、運行日志輸出保護、用戶信息輸入保護等;另一方面需要開發者在App實現方案中采用保護技術,如客戶端和服務器端通信過程的保護等。此次僅介紹App動態防護技術的實現思路,不討論具體的實現方案細節。
    最近Log4j的漏洞引起了很多師傅對JNDI注入漏洞利用的研究,淺藍師傅的文章探索高版本 JDK 下 JNDI漏洞的利用方法提出了很多關于繞過JNDI高版本限制的方法,本文主要是對文章中的部分方法進行分析并加上一些我個人的思考。 前言
    一顆小胡椒
    暫無描述
      亚洲 欧美 自拍 唯美 另类