go語言實現簡單的聊天室
阿新 • • 發佈:2018-04-20
tcp協議 golang聊天室通常聊天室的架構分為服務器端和客戶端:
服務器端:
接受來自於客戶端的連接請求並建立連接;
所有客戶端的連接會放進連接池中,用於廣播消息;
客戶端:
連接服務器;
向服務器發送消息;
接收服務器的廣播消息;
註意事項:
某一個客戶端斷開連接後需要從連接池中摘除,並不再接收廣播消息;
某一個客戶端斷開連接後不能影響服務器端或別的客戶端的連接;
詳細的代碼如下,文檔看註釋就好了,不再細說:
服務器:
server.go
package main import ( "net" "log" "fmt" ) func main() { port := "9090" Start(port) } // 啟動服務器 func Start(port string) { host := ":" + port // 獲取tcp地址 tcpAddr, err := net.ResolveTCPAddr("tcp4", host) if err != nil { log.Printf("resolve tcp addr failed: %v\n", err) return } // 監聽 listener, err := net.ListenTCP("tcp", tcpAddr) if err != nil { log.Printf("listen tcp port failed: %v\n", err) return } // 建立連接池,用於廣播消息 conns := make(map[string]net.Conn) // 消息通道 messageChan := make(chan string, 10) // 廣播消息 go BroadMessages(&conns, messageChan) // 啟動 for { fmt.Printf("listening port %s ...\n", port) conn, err := listener.AcceptTCP() if err != nil { log.Printf("Accept failed:%v\n", err) continue } // 把每個客戶端連接扔進連接池 conns[conn.RemoteAddr().String()] = conn fmt.Println(conns) // 處理消息 go Handler(conn, &conns, messageChan) } } // 向所有連接上的鄉親們發廣播 func BroadMessages(conns *map[string]net.Conn, messages chan string) { for { // 不斷從通道裏讀取消息 msg := <-messages fmt.Println(msg) // 向所有的鄉親們發消息 for key, conn := range *conns { fmt.Println("connection is connected from ", key) _, err := conn.Write([]byte(msg)) if err != nil { log.Printf("broad message to %s failed: %v\n", key, err) delete(*conns, key) } } } } // 處理客戶端發到服務端的消息,將其扔到通道中 func Handler(conn net.Conn, conns *map[string]net.Conn, messages chan string) { fmt.Println("connect from client ", conn.RemoteAddr().String()) buf := make([]byte, 1024) for { length, err := conn.Read(buf) if err != nil { log.Printf("read client message failed:%v\n", err) delete(*conns, conn.RemoteAddr().String()) conn.Close() break } // 把收到的消息寫到通道中 recvStr := string(buf[0:length]) messages <- recvStr } }
客戶端:
client.go
package main import ( "net" "log" "fmt" "os" ) func main() { Start(os.Args[1]) } func Start(tcpAddrStr string) { tcpAddr, err := net.ResolveTCPAddr("tcp4", tcpAddrStr) if err != nil { log.Printf("Resolve tcp addr failed: %v\n", err) return } // 向服務器撥號 conn, err := net.DialTCP("tcp", nil, tcpAddr) if err != nil { log.Printf("Dial to server failed: %v\n", err) return } // 向服務器發消息 go SendMsg(conn) // 接收來自服務器端的廣播消息 buf := make([]byte, 1024) for { length, err := conn.Read(buf) if err != nil { log.Printf("recv server msg failed: %v\n", err) conn.Close() os.Exit(0) break } fmt.Println(string(buf[0:length])) } } // 向服務器端發消息 func SendMsg(conn net.Conn) { username := conn.LocalAddr().String() for { var input string // 接收輸入消息,放到input變量中 fmt.Scanln(&input) if input == "/q" || input == "/quit" { fmt.Println("Byebye ...") conn.Close() os.Exit(0) } // 只處理有內容的消息 if len(input) > 0 { msg := username + " say:" + input _, err := conn.Write([]byte(msg)) if err != nil { conn.Close() break } } } }
測試方法:
編譯server.go和client.go;
打開終端,啟動server,默認會監聽9090端口;
再打開多個終端,啟動client,client啟動命令:client 服務器IP:9090;
在client中輸入字符並回車,可以看到別的終端都會收到消息;
go語言實現簡單的聊天室