用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 main import ( "bufio" "fmt" "net" ) // 用来记录所有的客户端连接 var ConnMap map[string]*net.TCPConn func 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 main import ( "bufio" "fmt" "net" ) func main() { var tcpAddr *net.TCPAddr tcpAddr,"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端,然后新开两个个终端,启动客户端,在其中一个客户端里键入聊天信息后回车,会发现另外一个客户端收到了刚刚发送的聊下天信息
完事大吉!
相关源码: https://git.oschina.net/victoriest/go-simple-tcp-server.git