首頁 > 軟體

Go語言實現一個簡單的並行聊天室的專案實戰

2022-03-18 19:00:40

寫在前面

Go語言在很多方面天然的具備很多便捷性,譬如網路程式設計,並行程式設計。而通道則又是Go語言實現並行程式設計的重要工具,因為其承擔著通道之間互相通訊的重任。並且因為其本身就是並行安全的,所以在某些場景下是非常好用的。

並行聊天伺服器

這裡主要是實現一個簡單的並行聊天伺服器。首先,使用者端可以在伺服器中註冊自己的資訊(登入以及退出),使用者端發出的所有的資訊由伺服器向各個使用者端進行轉發,或者換句話說是廣播。

具體程式碼

伺服器端

說的再多,沒有程式碼簡單明瞭,直接上程式碼~

package main

import (
    "bufio"
    "fmt"
    "log"
    "net"
)
type client chan <- string //定義一個單向的向外傳送資料的通道

var (
    entering = make(chan client)
    leaving = make(chan client)
    messages = make(chan string)
)

func main() {
    listener, err := net.Listen("tcp","localhost:8000")
    if err != nil {
        log.Fatal("network is broken", err)
    }
    go broadcaster()
    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Print(err)
            continue
        }
        go handleConn1(conn)
    }
}
func broadcaster()  {
    clients := make(map[client]bool) //儲存每個client的登入狀態
    for{
        select {
        case msg := <-messages:
            for cli := range clients {
                cli <- msg
            }
        case cli := <-entering:
            clients[cli] = true
        case cli := <-leaving:
            delete(clients,cli)
            close(cli)
        }
    }
}

func handleConn1(conn net.Conn)  {
    ch := make(chan string)
    go clientWriter(conn, ch)
    who := conn.RemoteAddr().String()
    ch <- "You are " + who
    entering <- ch
    messages <- who + "has arrived"

    input := bufio.NewScanner(conn)
    for input.Scan() {
        messages <- who + ":" + input.Text()
    }

    leaving <- ch
    messages <- who + "has left"
    conn.Close()
}

func clientWriter(conn net.Conn, ch <- chan string)  {
    for msg := range ch {
        fmt.Fprintln(conn, msg)
    }
}

使用者端

使用者端相對簡單,只是涉及到資訊的傳送和接受工作。

package main

import (
    "io"
    "log"
    "net"
    "os"
)

func main() {
    conn, err := net.Dial("tcp","localhost:8000")
    if err != nil {
        log.Fatal("Connected has been refused!",err)
    }
    defer conn.Close()
    go mesCopy(os.Stdout,conn)
    mesCopy(conn,os.Stdin)
}

func mesCopy(des io.Writer, res io.Reader)  {
    if _, err := io.Copy(des, res); err != nil {
        log.Print("wrong!")
    }
}

 總結

實現原理較為簡單,所以程式碼並沒有多少註釋,如果有任何疑問,歡迎留言討論。最後說一句,在MIT的課程中,其實並不是很推薦在並行程式設計中使用通道chan,除非你對其應用的場景和可能出現的情況有很好的把握,不然可能會出現很多不可預測的事情,譬如死鎖(見另外一篇部落格)。在這種時候,共用變數將會是一種很好的選擇,具體檢視go多執行緒實踐。

到此這篇關於Go語言實現一個簡單的並行聊天室的專案實戰的文章就介紹到這了,更多相關Go語言 並行聊天室內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com