第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Go : 在 For 循環(huán)中取消上下文

Go : 在 For 循環(huán)中取消上下文

Go
BIG陽 2022-11-08 17:17:39
我正在嘗試在 Golang 中創(chuàng)建一個 UDP 服務器來監(jiān)聽一個端口,例如。1234. 我有一個客戶端向這個服務器發(fā)送啟動/停止消息。收到消息“start”后,服務器將開始向該客戶端發(fā)送隨機數(shù)據(jù),在停止時,服務器將停止向客戶端發(fā)送。為此,我使用上下文來創(chuàng)建一個 goroutine 來發(fā)送數(shù)據(jù)并在它“停止”時取消它。我得到的錯誤是該程序適用于一個客戶端,但如果我再次啟動客戶端,則不會再次發(fā)送數(shù)據(jù)。任何幫助,將不勝感激?UDP服務器代碼:package mainimport (    "context"    "fmt"    "math/rand"    "net"    "time")func generateMessageToUDP(ctx context.Context, addr *net.UDPAddr) {    // stop writing to UDP    done := false    fmt.Println("Generating message to UDP client", addr)    conn, err := net.DialUDP("udp", nil, addr)    if err != nil {        fmt.Println("Error: ", err)    }    defer func(conn *net.UDPConn) {        err := conn.Close()        if err != nil {            fmt.Println("Error in closing the UDP Connection: ", err)        }    }(conn)    // write to address using UDP connection    go func() {        for i := 0; !done; i++ {            RandomInt := rand.Intn(100)            fmt.Println("Random Int: ", RandomInt)            _, err = conn.Write([]byte(fmt.Sprintf("%d", RandomInt)))            fmt.Println("Sent ", RandomInt, " to ", addr)            time.Sleep(time.Second * 1)        }    }()    <-ctx.Done()    fmt.Println("Stopping writing to UDP client", addr)    done = true}//var addr *net.UDPAddr//var conn *net.UDPConnfunc main() {    fmt.Println("Hi this is a UDP server")    udpServer, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 5010})    if err != nil {        fmt.Println("Error: ", err)    }    defer func(udpServer *net.UDPConn) {        err := udpServer.Close()        if err != nil {            fmt.Println("Error in closing the UDP Connection: ", err)        }    }
查看完整描述

2 回答

?
交互式愛情

TA貢獻1712條經(jīng)驗 獲得超3個贊

你必須小心你正在做的事情。

  • 避免數(shù)據(jù)競爭(完成變量由兩個不同的例程讀取/寫入,沒有同步機制)https://go.dev/doc/articles/race_detector

  • 每次程序開始向新客戶端發(fā)送消息時,不要制作新的撥號器。這將打開一個新的本地地址并使用它將其發(fā)送給客戶端??蛻舳藢牧硪粋€地址接收消息,通常應該忽略這些消息,因為它沒有啟動與該遠程的任何交換。

  • 不要將客戶端生命周期與程序上下文生命周期混淆。在提供的代碼中,客戶端發(fā)送停止消息將觸發(fā)整個程序的取消功能,它將停止所有客戶端。為每個客戶端創(chuàng)建一個新的上下文,派生自程序上下文,在收到停止消息時取消相關(guān)的客戶端上下文。

  • UDP conns 由所有客戶端共享,不能因為程序正在為客戶端提供服務而停止偵聽傳入的數(shù)據(jù)包。IE 調(diào)用generateMessageToUDP應該在另一個例程中執(zhí)行。

以下是針對這些評論的修訂版。

添加Avar peers map[string]peer以將遠程地址與上下文匹配。類型peer定義為struct {stop  func();since time.Time}。在接收到開始消息后,將與派生上下文一起peer添加到 中。然后,新客戶端將在不同的例程中提供服務,該例程綁定到新創(chuàng)建的上下文和服務器套接字。收到停止消息后,程序執(zhí)行查找,然后取消關(guān)聯(lián)的對等上下文并忘記對等。mappctx, pcancel := context.WithCancel(ctx)go generateMessageToUDP(pctx, udpServer, addr)peer, ok := peers[addr.String()]peer.stop(); delete(peers, addr.String())

package main


import (

    "context"

    "fmt"

    "math/rand"

    "net"

    "time"

)


func generateMessageToUDP(ctx context.Context, conn *net.UDPConn, addr *net.UDPAddr) {

    fmt.Println("Generating message to UDP client", addr)

    go func() {

        for i := 0; ; i++ {

            RandomInt := rand.Intn(100)

            d := []byte(fmt.Sprintf("%d", RandomInt))

            conn.WriteTo(d, addr)

            time.Sleep(time.Second * 1)

        }

    }()

    <-ctx.Done()

    fmt.Println("Stopping writing to UDP client", addr)

}


//var addr *net.UDPAddr

//var conn *net.UDPConn


func main() {

    fmt.Println("Hi this is a UDP server")

    udpServer, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 5010})

    if err != nil {

        fmt.Println("Error: ", err)

    }

    defer func(udpServer *net.UDPConn) {

        err := udpServer.Close()

        if err != nil {

            fmt.Println("Error in closing the UDP Connection: ", err)

        }

    }(udpServer)

    // create a buffer to read data into

    type peer struct {

        stop  func()

        since time.Time

    }

    peers := map[string]peer{}

    buffer := make([]byte, 1024)

    ctx, cancel := context.WithCancel(context.Background())

    defer cancel()

    for {

        // read the incoming connection into the buffer

        n, addr, err := udpServer.ReadFromUDP(buffer)

        if err != nil {

            fmt.Println("Error: ", err)

        }

        fmt.Println("Received ", string(buffer[0:n]), " from ", addr)

        if string(buffer[0:n]) == "stop" {

            fmt.Println("Stopped listening")

            peer, ok := peers[addr.String()]

            if !ok {

                continue

            }

            peer.stop()

            delete(peers, addr.String())

            continue

        } else if string(buffer[0:n]) == "start" {

            peer, ok := peers[addr.String()]

            if ok {

                continue

            }

            pctx, pcancel := context.WithCancel(ctx)

            peer.stop = pcancel

            peer.since = time.Now()

            peers[addr.String()] = peer

            // send a response back to the client

            _, err = udpServer.WriteToUDP([]byte("Hi, I am a UDP server"), addr)

            if err != nil {

                fmt.Println("Error: ", err)

            }

            // start a routine to generate messages to the client

            go generateMessageToUDP(pctx, udpServer, addr)

        } else if string(buffer[0:n]) == "ping" {

            peer, ok := peers[addr.String()]

            if !ok {

                continue

            }

            peer.since = time.Now()

            peers[addr.String()] = peer

        } else {

            fmt.Println("Unknown command")

        }

        for addr, p := range peers {

            if time.Since(p.since) > time.Minute {

                fmt.Println("Peer timedout")

                p.stop()

                delete(peers, addr)

            }

        }

    }

}

-- go.mod --

module play.ground

-- client.go --

package main


import (

    "fmt"

    "log"

    "net"

    "time"

)


func main() {

    fmt.Println("Hello, I am a client")


    // Create a new client

    localAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:5011")

    client3, err := net.DialUDP("udp", localAddr, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 5010})

    if err != nil {

        fmt.Println(err)

        return

    }

    defer client3.Close()

    var n int

    n, err = client3.Write([]byte("start"))

    if err != nil {

        fmt.Println(err)

        return

    }

    log.Println(n)

    now := time.Now()

    b := make([]byte, 2048)

    for time.Since(now) < time.Second*10 {

        n, addr, err := client3.ReadFrom(b)

        fmt.Println(n, addr, err)

        if err != nil {

            fmt.Println(err)

            continue

        }

        if addr.String() == "127.0.0.1:5010" {

            m := b[:n]

            fmt.Println("message:", string(m))

        }

    }

    fmt.Println("Sending stop message")

    _, err = client3.Write([]byte("stop"))

    if err != nil {

        fmt.Println(err)

    }

}


    go func() {

        for i := 0; ; i++ {

            RandomInt := rand.Intn(100)

            d := []byte(fmt.Sprintf("%d", RandomInt))

            conn.WriteTo(d, addr)

            time.Sleep(time.Second * 1)

        }

    }()

我將在上下文通道上寫入缺失的選擇作為練習留給讀者,以確定例程是否應該退出。


查看完整回答
反對 回復 2022-11-08
?
叮當貓咪

TA貢獻1776條經(jīng)驗 獲得超12個贊

好的,我在服務器上做了一個簡單的修改,并在創(chuàng)建上下文之前添加了一個標簽 Start,當我取消上下文時,我添加了 goto 標簽。這意味著當任務被取消時,它將再次創(chuàng)建上下文并開始執(zhí)行其工作



查看完整回答
反對 回復 2022-11-08
  • 2 回答
  • 0 關(guān)注
  • 144 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學習伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號