最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Go?goroutine實(shí)現(xiàn)一個(gè)簡(jiǎn)單的聊天服務(wù)

 更新時(shí)間:2023年06月08日 08:50:55   作者:架構(gòu)精進(jìn)之路  
對(duì)于聊天服務(wù),想必大家都不會(huì)陌生,因?yàn)樵谖覀兊纳钪薪?jīng)常會(huì)用到,本文我們用?Go?并發(fā)來(lái)實(shí)現(xiàn)一個(gè)聊天服務(wù)器,這個(gè)程序可以讓一些用戶通過(guò)服務(wù)器向其它所有用戶廣播文本消息,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下

對(duì)于聊天服務(wù),想必大家都不會(huì)陌生,因?yàn)樵谖覀兊纳钪薪?jīng)常會(huì)用到。

我們用 Go 并發(fā)來(lái)實(shí)現(xiàn)一個(gè)聊天服務(wù)器,這個(gè)程序可以讓一些用戶通過(guò)服務(wù)器向其它所有用戶廣播文本消息。

這個(gè)程序中有四種 goroutine。
main 和 broadcaster 各自是一個(gè) goroutine 實(shí)例,每一個(gè)客戶端的連接都會(huì)有一個(gè)handleConn 和 clientWriter 的 goroutine。
broadcaster 是 select 用法的不錯(cuò)的樣例,因?yàn)樗枰幚砣N不同類型的消息。

下面我們來(lái)演示的 main goroutine 的工作,是 listen 和 accept (網(wǎng)絡(luò)編程里的概念)從客戶端過(guò)來(lái)的連接。對(duì)每一個(gè)連接,程序都會(huì)建立一個(gè)新的 handleConn 的 goroutine。

func main() {
    listener, err := net.Listen("tcp", "localhost:8000")
    if err != nil {
        log.Fatal(err)
    }
    go broadcaster()
    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Print(err)
            continue
        }
        go handleConn(conn)
    }
}

然后是broadcaster的goroutine。

他的內(nèi)部變量clients會(huì)記錄當(dāng)前建立連接的客戶端集合,其記錄的內(nèi)容是每一個(gè)客戶端的消息發(fā)出channel的“資格”信息。

type client chan<- string // an outgoing message channel
var (
    entering = make(chan client)
    leaving  = make(chan client)
    messages = make(chan string) // all incoming client messages
)
func broadcaster() {
    clients := make(map[client]bool) // all connected clients
    for {
        select {
        case msg := <-messages:
            // Broadcast incoming message to all
            // clients' outgoing message channels.
            for cli := range clients {
                cli <- msg
            }
        case cli := <-entering:
            clients[cli] = true
        case cli := <-leaving:
            delete(clients, cli)
            close(cli)
        }
    }
}

broadcaster監(jiān)聽(tīng)來(lái)自全局的entering和leaving的channel來(lái)獲知客戶端的到來(lái)和離開(kāi)事件。

當(dāng)其接收到其中的一個(gè)事件時(shí),會(huì)更新clients集合,當(dāng)該事件是離開(kāi)行為時(shí),它會(huì)關(guān)閉客戶端的消息發(fā)送channel。broadcaster也會(huì)監(jiān)聽(tīng)全局的消息channel,所有的客戶端都會(huì)向這個(gè)channel中發(fā)送消息。當(dāng)broadcaster接收到什么消息時(shí),就會(huì)將其廣播至所有連接到服務(wù)端的客戶端。

現(xiàn)在讓我們看看每一個(gè)客戶端的goroutine。

handleConn函數(shù)會(huì)為它的客戶端創(chuàng)建一個(gè)消息發(fā)送channel并通過(guò)entering channel來(lái)通知客戶端的到來(lái)。然后它會(huì)讀取客戶端發(fā)來(lái)的每一行文本,并通過(guò)全局的消息channel來(lái)將這些文本發(fā)送出去,并為每條消息帶上發(fā)送者的前綴來(lái)標(biāo)明消息身份。當(dāng)客戶端發(fā)送完畢后,handleConn會(huì)通過(guò)leaving這個(gè)channel來(lái)通知客戶端的離開(kāi)并關(guān)閉連接。

func handleConn(conn net.Conn) {
    ch := make(chan string) // outgoing client messages
    go clientWriter(conn, ch)
    who := conn.RemoteAddr().String()
    ch <- "You are " + who
    messages <- who + " has arrived"
    entering <- ch
    input := bufio.NewScanner(conn)
    for input.Scan() {
        messages <- who + ": " + input.Text()
    }
    // NOTE: ignoring potential errors from input.Err()
    leaving <- ch
    messages <- who + " has left"
    conn.Close()
}
func clientWriter(conn net.Conn, ch <-chan string) {
    for msg := range ch {
        fmt.Fprintln(conn, msg) // NOTE: ignoring network errors
    }
}

另外,handleConn為每一個(gè)客戶端創(chuàng)建了一個(gè)clientWriter的goroutine,用來(lái)接收向客戶端發(fā)送消息的channel中的廣播消息,并將它們寫(xiě)入到客戶端的網(wǎng)絡(luò)連接??蛻舳说淖x取循環(huán)會(huì)在broadcaster接收到leaving通知并關(guān)閉了channel后終止。

下面演示的是當(dāng)服務(wù)器有兩個(gè)活動(dòng)的客戶端連接,并且在兩個(gè)窗口中運(yùn)行的情況,使用netcat來(lái)聊天:

$ go build gopl.io/ch8/chat
$ go build gopl.io/ch8/netcat3
$ ./chat &
$ ./netcat3
You are 127.0.0.1:64208               $ ./netcat3
127.0.0.1:64211 has arrived           You are 127.0.0.1:64211
Hi!
127.0.0.1:64208: Hi!                  127.0.0.1:64208: Hi!
                                      Hi yourself.
127.0.0.1:64211: Hi yourself.         127.0.0.1:64211: Hi yourself.
^C
                                      127.0.0.1:64208 has left
$ ./netcat3
You are 127.0.0.1:64216               127.0.0.1:64216 has arrived
                                      Welcome.
127.0.0.1:64211: Welcome.             127.0.0.1:64211: Welcome.
                                      ^C
127.0.0.1:64211 has left”

當(dāng)與n個(gè)客戶端保持聊天session時(shí),這個(gè)程序會(huì)有2n+2個(gè)并發(fā)的goroutine,然而這個(gè)程序卻并不需要顯式的鎖。clients這個(gè)map被限制在了一個(gè)獨(dú)立的goroutine中,broadcaster,所以它不能被并發(fā)地訪問(wèn)。

多個(gè)goroutine共享的變量只有這些channel和net.Conn的實(shí)例,兩個(gè)東西都是并發(fā)安全的。

到此這篇關(guān)于基于Go goroutine實(shí)現(xiàn)一個(gè)簡(jiǎn)單的聊天服務(wù)的文章就介紹到這了,更多相關(guān)Go goroutine 聊天服務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語(yǔ)言使用AES加密解密的示例代碼

    Go語(yǔ)言使用AES加密解密的示例代碼

    這篇文章主要介紹了Go語(yǔ)言使用AES加密解密的示例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09
  • Go語(yǔ)言單線程運(yùn)行也會(huì)有的并發(fā)問(wèn)題解析

    Go語(yǔ)言單線程運(yùn)行也會(huì)有的并發(fā)問(wèn)題解析

    這篇文章主要為大家介紹了Go語(yǔ)言單線程運(yùn)行的并發(fā)問(wèn)題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 深入淺析Go中三個(gè)點(diǎn)(...)用法

    深入淺析Go中三個(gè)點(diǎn)(...)用法

    這篇文章主要介紹了深入淺析Go中三個(gè)點(diǎn)(...)用法,需要的朋友可以參考下
    2021-10-10
  • golang開(kāi)啟mod后import報(bào)紅的簡(jiǎn)單解決方案

    golang開(kāi)啟mod后import報(bào)紅的簡(jiǎn)單解決方案

    這篇文章主要給大家介紹了關(guān)于golang開(kāi)啟mod后import報(bào)紅的簡(jiǎn)單解決方案,文中通過(guò)圖文將解決的辦法介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2024-01-01
  • 使用Gomock進(jìn)行單元測(cè)試的方法示例

    使用Gomock進(jìn)行單元測(cè)試的方法示例

    這篇文章主要介紹了使用Gomock進(jìn)行單元測(cè)試的方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • GO中公平鎖和非公平鎖的具體使用

    GO中公平鎖和非公平鎖的具體使用

    公平鎖和非公平鎖是計(jì)算機(jī)科學(xué)中的兩種鎖機(jī)制,它們主要用于多線程編程,以控制對(duì)共享資源的訪問(wèn),本文主要介紹了GO中公平鎖和非公平鎖的具體使用,感興趣的可以了解一下
    2024-08-08
  • Golang利用Template模板動(dòng)態(tài)生成文本

    Golang利用Template模板動(dòng)態(tài)生成文本

    Go語(yǔ)言中的Go?Template是一種用于生成文本輸出的簡(jiǎn)單而強(qiáng)大的模板引擎,它提供了一種靈活的方式來(lái)生成各種格式的文本,下面我們就來(lái)看看具體如何使用Template實(shí)現(xiàn)動(dòng)態(tài)文本生成吧
    2023-09-09
  • Go讀取配置文件的方法總結(jié)

    Go讀取配置文件的方法總結(jié)

    我們常見(jiàn)的配置文件的格式一般有:XML、JSON、INI、YAML、env和.properties,本文小編為大家整理了Go語(yǔ)言讀取這些格式的配置文件的方法,希望對(duì)大家有所幫助
    2023-10-10
  • 深入探究Golang中l(wèi)og標(biāo)準(zhǔn)庫(kù)的使用

    深入探究Golang中l(wèi)og標(biāo)準(zhǔn)庫(kù)的使用

    Go?語(yǔ)言標(biāo)準(zhǔn)庫(kù)中的?log?包設(shè)計(jì)簡(jiǎn)潔明了,易于上手,可以輕松記錄程序運(yùn)行時(shí)的信息、調(diào)試錯(cuò)誤以及跟蹤代碼執(zhí)行過(guò)程中的問(wèn)題等。本文主要來(lái)深入探究?log?包的使用和原理,幫助讀者更好地了解和掌握它
    2023-05-05
  • golang開(kāi)發(fā)go包依賴管理godep使用教程

    golang開(kāi)發(fā)go包依賴管理godep使用教程

    這篇文章主要為大家介紹了golang開(kāi)發(fā)go包依賴管理godep使用教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2021-11-11

最新評(píng)論

芮城县| 阜康市| 岳阳县| 兰西县| 新余市| 濮阳县| 那坡县| 红原县| 阳江市| 天峻县| 镇宁| 皮山县| 察哈| 肃宁县| 贡山| 安顺市| 息烽县| 咸宁市| 潜江市| 富裕县| 类乌齐县| 罗城| 峨眉山市| 西峡县| 浦东新区| 望都县| 忻城县| 黑龙江省| 泽库县| 盐边县| 克东县| 剑阁县| 东安县| 乌鲁木齐县| 翼城县| 永川市| 突泉县| 洪雅县| 晋州市| 封丘县| 金川县|