這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
用Golang實現 文本廣播式聊天伺服器/用戶端
本節, 我們將一步一步的把上一節完成的echo伺服器/用戶端改造成一個文本資訊的聊天室
服務端的改動
伺服器為了實現聊天資訊的群體廣播, 需要記錄所有串連到伺服器的用戶端資訊, 所以, 我們需要添加一個集合來儲存所有用戶端的串連:
var ConnMap map[string]*net.TCPConn
接著, 每次當有新的用戶端串連到伺服器時, 需要把這個用戶端串連行資訊加入集合:
ConnMap[tcpConn.RemoteAddr().String()] = tcpConn
當伺服器收到用戶端的聊天資訊時, 需要廣播到所有用戶端, 所以我們需要利用上面儲存TCPConn的map來遍曆所有TCPConn進行廣播, 用以下方法實現:
func boradcastMessage(message string) { b := []byte(message) for _, conn := range ConnMap { conn.Write(b) }}
用戶端代碼改動
用戶端代碼改動相對簡單, 只是加入了使用者自己輸入聊天資訊的功能, 在串連成功並且 啟動了訊息接收的gorountine後, 加入以下代碼:
for { var msg string fmt.Scanln(&msg) if msg == "quit" { break } b := []byte(msg + "\n") conn.Write(b) }
完整的服務端代碼如下:
server.go
package mainimport ( "bufio" "fmt" "net")// 用來記錄所有的用戶端串連var ConnMap map[string]*net.TCPConnfunc main() { var tcpAddr *net.TCPAddr ConnMap = make(map[string]*net.TCPConn) tcpAddr, _ = net.ResolveTCPAddr("tcp", "127.0.0.1:9999") tcpListener, _ := net.ListenTCP("tcp", tcpAddr) defer tcpListener.Close() for { tcpConn, err := tcpListener.AcceptTCP() if err != nil { continue } fmt.Println("A client connected : " + tcpConn.RemoteAddr().String()) // 新串連加入map ConnMap[tcpConn.RemoteAddr().String()] = tcpConn go tcpPipe(tcpConn) }}func tcpPipe(conn *net.TCPConn) { ipStr := conn.RemoteAddr().String() defer func() { fmt.Println("disconnected :" + ipStr) conn.Close() }() reader := bufio.NewReader(conn) for { message, err := reader.ReadString('\n') if err != nil { return } fmt.Println(conn.RemoteAddr().String() + ":" + string(message)) // 這裡返回訊息改為了廣播 boradcastMessage(conn.RemoteAddr().String() + ":" + string(message)) }}func boradcastMessage(message string) { b := []byte(message) // 遍曆所有用戶端並發送訊息 for _, conn := range ConnMap { conn.Write(b) }}
用戶端完整代碼如下:
client.go
package mainimport ( "bufio" "fmt" "net")func main() { var tcpAddr *net.TCPAddr tcpAddr, _ = net.ResolveTCPAddr("tcp", "127.0.0.1:9999") conn, _ := net.DialTCP("tcp", nil, tcpAddr) defer conn.Close() fmt.Println("connected!") go onMessageRecived(conn) // 控制台聊天功能加入 for { var msg string fmt.Scanln(&msg) if msg == "quit" { break } b := []byte(msg + "\n") conn.Write(b) }}func onMessageRecived(conn *net.TCPConn) { reader := bufio.NewReader(conn) for { msg, err := reader.ReadString('\n') fmt.Println(msg) if err != nil { quitSemaphore <- true break } }}
最後分別編譯server與client試試效果吧!
go build server.go
go build client.go
先啟動server端, 然後新開兩個個終端, 啟動用戶端, 在其中一個用戶端裡鍵入聊天資訊後斷行符號, 會發現另外一個用戶端收到了剛剛發送的聊下天資訊
完事大吉!