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

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

如何訪問所有連接的 tcp 客戶端的變量?

如何訪問所有連接的 tcp 客戶端的變量?

Go
當(dāng)年話下 2023-06-19 17:12:00
我正在用 go 編寫的寵物項(xiàng)目中設(shè)置一個(gè) tcp 服務(wù)器。我希望能夠維護(hù)所有連接的客戶端的一部分,然后在新客戶端連接到我的服務(wù)器或從我的服務(wù)器斷開連接時(shí)修改它。我現(xiàn)在的主要心理障礙是我是否應(yīng)該聲明一個(gè)包級切片,或者只是將一個(gè)切片傳遞給我的處理程序。我的第一個(gè)想法是聲明我的ClientList切片(我知道切片可能不是我最好的選擇,但我決定暫時(shí)保留它)作為包級變量。雖然我認(rèn)為這行得通,但我看到許多帖子不鼓勵(lì)使用它們。我的另一個(gè)想法是在我的主函數(shù)中聲明ClientList為一個(gè)切片,然后我傳遞ClientList給我的HandleClient函數(shù),所以每當(dāng)客戶端連接/斷開連接時(shí),我都可以調(diào)用AddClient或RemoveClient傳遞這個(gè)切片并添加/刪除適當(dāng)?shù)目蛻舳?。此?shí)現(xiàn)如下所示。代碼肯定還有其他問題,但我一直在努力思考一些看起來應(yīng)該非常簡單的事情。type Client struct {    Name string      Conn net.Conn}type ClientList []*Client// Identify is used to set the name of the clientfunc (cl *Client) Identify() error {// code here to set the client's name in the based on input from client}// This is not a threadsafe way to do this - need to use mutex/channelsfunc (cList *ClientList) AddClient(cl *Client) {    *cList = append(*cList, cl)}func (cl *Client) HandleClient(cList *ClientList) {    defer cl.Conn.Close()    cList.AddClient(cl)    err := cl.Identify()    if err != nil {        log.Println(err)        return    }    for {        err := cl.Conn.SetDeadline(time.Now().Add(20 * time.Second))        if err != nil {            log.Println(err)            return        }        cl.Conn.Write([]byte("What command would you like to perform?\n"))        netData, err := bufio.NewReader(cl.Conn).ReadString('\n')        if err != nil {            log.Println(err)            return        }        cmd := strings.TrimSpace(string(netData))        if cmd == "Ping" {            cl.Ping() //sends a pong msg back to client        } else {            cl.Conn.Write([]byte("Unsupported command at this time\n"))        }    }}func main() {    arguments := os.Args    PORT := ":" + arguments[1]    l, err := net.Listen("tcp4", PORT)    if err != nil {        fmt.Println(err)        return    }從我最初的測試來看,這似乎有效。我能夠打印出我的客戶列表,我可以看到正在添加新客戶,并且在Identify()調(diào)用之后也添加了他們的名字。當(dāng)我使用 -race 標(biāo)志運(yùn)行它時(shí),我確實(shí)收到了數(shù)據(jù)競爭警告,所以我知道我需要一種線程安全的方式來處理添加的客戶端。當(dāng)我添加它時(shí)刪除客戶端也是如此。將我的 ClientList 傳遞到 中是否有任何其他問題我可能會遺漏HandleClient,或者我將 ClientList 聲明為包級變量可以獲得任何好處?
查看完整描述

1 回答

?
拉莫斯之舞

TA貢獻(xiàn)1820條經(jīng)驗(yàn) 獲得超10個(gè)贊

這種方法存在幾個(gè)問題。


首先,您的代碼包含數(shù)據(jù)競爭:每個(gè) TCP 連接都由一個(gè)單獨(dú)的 goroutine 提供服務(wù),并且它們都試圖同時(shí)修改切片。


go build -race您可能會嘗試使用(或go install -race— 無論您使用什么)構(gòu)建代碼,并看到它因啟用的運(yùn)行時(shí)檢查而崩潰。


這個(gè)很容易修復(fù)。最直接的方法是在類型中添加一個(gè)互斥變量ClientList:


type ClientList struct {

  mu      sync.Mutex

  clients []*Client

}

…并使類型的方法在改變字段時(shí)保持互斥量clients,如下所示:


func (cList *ClientList) AddClient(cl *Client) {

  cList.mu.Lock()

  defer cList.mu.Unlock()


  cList.clients = append(cList.clients, o)

}

(如果你曾經(jīng)遇到過你的ClientList類型的典型使用模式是頻繁調(diào)用只讀取包含列表的方法,你可以開始使用sync.RWLock允許多個(gè)并發(fā)讀取器的類型。)


其次,我將“識別”客戶端的部分從處理函數(shù)中分離出來。至此,在handler中,如果識別失敗,handler退出,但client不會退市。


我會說最好預(yù)先識別它,并且只有在認(rèn)為客戶沒問題時(shí)才運(yùn)行處理程序。


此外,值得RemoveClient在處理程序主體的頂部添加一個(gè)延遲調(diào)用,以便在處理程序完成時(shí)正確地取消列出客戶端。


IOW,我希望看到這樣的事情:


func (cl *Client) HandleClient(cList *ClientList) {

    defer cl.Conn.Close()


    err := cl.Identify()

    if err != nil {

        log.Println(err)

        return

    }


    cList.AddClient(cl)

    defer cList.RemoveClient(cl)


    // ... the rest of the code

}


查看完整回答
反對 回復(fù) 2023-06-19
  • 1 回答
  • 0 關(guān)注
  • 135 瀏覽

添加回答

舉報(bào)

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號

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