Go 群聊 ( goroutine )

來源:互聯網
上載者:User

前言

看了無聞老師的一節關於 goroutine 與 channel 的講解課堂,感覺不是很明白,所以決定來實現一個聊天室的功能

為什麼是群聊呢?

因為群聊相對邏輯簡單些

註:本栗子只用到了 goroutine 並沒有用到 channel

概述

1.聊天室的組成

聊天室分為兩個部分,分別是:

  • 服務端
  • 用戶端

然後,一般情況下我們互相聊天使用的都只是用戶端而已,服務端只是起到調度的作用

2.資訊發送與接收的流程

假設我們有 服務端(S) 用戶端(C1) 用戶端(C2) 用戶端(C3)

並且 S 已經 與 C1 C2 C3 建立了串連

理論上的流程是這樣的:

  1. C1S 發出資訊
  2. S 接收到資訊
  3. S 將接收到的資訊廣播給 C2 C3
  4. C2 C3 接收資訊

實踐

1.服務端

1) 代碼

package mainimport (    "time"    "fmt"    "net")// 用戶端 map var client_map =  make(map[string]*net.TCPConn)// 監聽請求func listen_client(ip_port string) {    tcpAddr, _ := net.ResolveTCPAddr("tcp", ip_port)    tcpListener, _ := net.ListenTCP("tcp", tcpAddr)    for {// 不停地接收        client_con, _ := tcpListener.AcceptTCP()// 監聽請求串連        client_map[client_con.RemoteAddr().String()] = client_con// 將串連添加到 map        go add_receiver(client_con)        fmt.Println("使用者 : ", client_con.RemoteAddr().String(), " 已串連.")    }}// 向串連添加接收器func add_receiver(current_connect *net.TCPConn) {    for {        byte_msg := make([]byte, 2048)        len, err := current_connect.Read(byte_msg)        if err != nil { current_connect.Close() }        fmt.Println(string(byte_msg[:len]))        msg_broadcast(byte_msg[:len], current_connect.RemoteAddr().String())    }}// 廣播給所有 clientfunc msg_broadcast(byte_msg []byte, key string) {    for k, con := range client_map {        if k != key { con.Write(byte_msg) }    }}// 主函數func main() {    fmt.Println("服務已啟動...")    time.Sleep(1 * time.Second)    fmt.Println("等待用戶端請求串連...")    go listen_client("127.0.0.1:1801")    select{}}    

b) 描述

可以看到,撇開 main 函數,一共有 2 個 routine,分別是:

  1. 監聽串連
  2. 接收訊息(廣播訊息也在這裡)

2.用戶端

a) 代碼

package mainimport (    "fmt"    "net"    "os"    "bufio")// 使用者名稱var login_name string// 本機串連var self_connect *net.TCPConn// 讀取行文本var reader = bufio.NewReader(os.Stdin)// 建立串連func connect(addr string) {    tcp_addr, _ := net.ResolveTCPAddr("tcp", addr) // 使用tcp    con, err := net.DialTCP("tcp", nil, tcp_addr) // 撥號    self_connect = con    if err != nil {        fmt.Println("伺服器串連失敗")        os.Exit(1)    }    go msg_sender()    go msg_receiver()}// 訊息接收器func msg_receiver() {    buff := make([]byte, 2048)    for {        len, _ := self_connect.Read(buff) // 讀取訊息        fmt.Println(string(buff[:len]))    }}// 訊息發送器func msg_sender() {    for {        read_line_msg, _, _ := reader.ReadLine()        read_line_msg = []byte(login_name + " : " + string(read_line_msg))        self_connect.Write(read_line_msg)    }}// 主函數func main() {    fmt.Println("請問您怎麼稱呼?")    name, _, _ := reader.ReadLine()    login_name = string(name)    connect("127.0.0.1:1801")    select{}}

b) 描述

同樣,用戶端也是有兩個 routine 組成:

  1. 訊息接收器
  2. 訊息發送器

建立串連在主線程完成

3.

a) 服務端

b) 用戶端_1

c) 用戶端_2

結尾

這裡並沒有用到 channel

小栗子僅為經驗總結,學習交流而記

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.