欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Go?goroutine實現(xiàn)一個簡單的聊天服務

 更新時間:2023年06月08日 08:50:55   作者:架構精進之路  
對于聊天服務,想必大家都不會陌生,因為在我們的生活中經(jīng)常會用到,本文我們用?Go?并發(fā)來實現(xiàn)一個聊天服務器,這個程序可以讓一些用戶通過服務器向其它所有用戶廣播文本消息,文中通過代碼示例介紹的非常詳細,需要的朋友可以參考下

對于聊天服務,想必大家都不會陌生,因為在我們的生活中經(jīng)常會用到。

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

這個程序中有四種 goroutine。
main 和 broadcaster 各自是一個 goroutine 實例,每一個客戶端的連接都會有一個handleConn 和 clientWriter 的 goroutine。
broadcaster 是 select 用法的不錯的樣例,因為它需要處理三種不同類型的消息。

下面我們來演示的 main goroutine 的工作,是 listen 和 accept (網(wǎng)絡編程里的概念)從客戶端過來的連接。對每一個連接,程序都會建立一個新的 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。

他的內部變量clients會記錄當前建立連接的客戶端集合,其記錄的內容是每一個客戶端的消息發(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)聽來自全局的entering和leaving的channel來獲知客戶端的到來和離開事件。

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

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

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

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為每一個客戶端創(chuàng)建了一個clientWriter的goroutine,用來接收向客戶端發(fā)送消息的channel中的廣播消息,并將它們寫入到客戶端的網(wǎng)絡連接??蛻舳说淖x取循環(huán)會在broadcaster接收到leaving通知并關閉了channel后終止。

下面演示的是當服務器有兩個活動的客戶端連接,并且在兩個窗口中運行的情況,使用netcat來聊天:

$ 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”

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

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

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

相關文章

  • go語言通過zlib壓縮數(shù)據(jù)的方法

    go語言通過zlib壓縮數(shù)據(jù)的方法

    這篇文章主要介紹了go語言通過zlib壓縮數(shù)據(jù)的方法,實例分析了Go語言中zlib的使用技巧,需要的朋友可以參考下
    2015-03-03
  • 詳解Go語言中make和new的區(qū)別

    詳解Go語言中make和new的區(qū)別

    Go語言中,有兩個比較雷同的內置函數(shù),分別是new和make方法,那他們有什么區(qū)別呢?本文將通過一些示例為大家詳細介紹一下,感興趣的可以了解一下
    2023-02-02
  • Redis?BloomFilter布隆過濾器原理與實現(xiàn)

    Redis?BloomFilter布隆過濾器原理與實現(xiàn)

    你在開發(fā)或者面試過程中,有沒有遇到過?海量數(shù)據(jù)需要查重,緩存穿透怎么避免等等這樣的問題呢?下面這個東西超棒,好好了解下,面試過關斬將,凸顯你的不一樣
    2022-10-10
  • 使用Go重構流式日志網(wǎng)關的實戰(zhàn)分享

    使用Go重構流式日志網(wǎng)關的實戰(zhàn)分享

    流式日志網(wǎng)關的主要功能是提供?HTTP?接口,接收?CDN?邊緣節(jié)點上報的各類日志(訪問日志/報錯日志/計費日志等),將日志作預處理并分流到多個的?Kafka?集群和?Topic?中,本文就給大家分享如何使用?Go?重構流式日志網(wǎng)關
    2023-06-06
  • Go單體服務開發(fā)最佳實踐總結

    Go單體服務開發(fā)最佳實踐總結

    這篇文章主要介紹了Go單體服務開發(fā)最佳實踐,通過本文詳細跟大家分享一下如何使用?go-zero?快速開發(fā)一個有多個模塊的單體服務,需要的朋友可以參考下
    2022-04-04
  • xorm根據(jù)數(shù)據(jù)庫生成go model文件的操作

    xorm根據(jù)數(shù)據(jù)庫生成go model文件的操作

    這篇文章主要介紹了xorm根據(jù)數(shù)據(jù)庫生成go model文件的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang拾遺之指針和接口的使用詳解

    Golang拾遺之指針和接口的使用詳解

    拾遺主要是收集和golang相關的瑣碎知識,這篇文章主要是為大家整理了Golang中指針和接口的使用方法,文中的示例代碼講解詳細,需要的可以參考一下
    2023-02-02
  • Go網(wǎng)絡編程TCP抓包實操示例探究

    Go網(wǎng)絡編程TCP抓包實操示例探究

    作為一名軟件開發(fā)者,網(wǎng)絡編程是必備知識,本文通過?Go?語言實現(xiàn)?TCP?套接字編程,并結合?tcpdump?工具,展示它的三次握手、數(shù)據(jù)傳輸以及四次揮手的過程,幫助讀者更好地理解?TCP?協(xié)議與?Go?網(wǎng)絡編程
    2024-01-01
  • 詳解Go語言中iota的應用

    詳解Go語言中iota的應用

    在本文中,小編將帶著大家深入探討?iota?的神奇力量,包括?iota?的介紹和應用場景以及使用技巧和注意事項,準備好了嗎,準備一杯你最喜歡的飲料或茶,隨著本文一探究竟吧
    2023-07-07
  • Golang實現(xiàn)文件傳輸功能

    Golang實現(xiàn)文件傳輸功能

    這篇文章主要為大家詳細介紹了Golang實現(xiàn)文件傳輸功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07

最新評論