goland 簡單聊天室服務端
阿新 • • 發佈:2019-01-04
nag rename accept lis read 發送消息 listen ddr quit
package main import ( "fmt" "net" "strings" "time" ) type Client struct { C chan string //用於發送數據的管道 Name string //用戶名 Address string //IP地址 } //保存在線用戶 var onLineMap map[string]Client var message = make(chan string) func Manager() { onLineMap = make(map[string]Client) for { msg := <-message //阻塞等待消息 for _, cli := range onLineMap { cli.C <- msg } } } //發送消息給客戶端 func WriteMessageToClient(cli Client, conn net.Conn) { for msg := range cli.C { //發送消息 conn.Write([]byte(msg + "\n")) } } func MakeMsg(cli Client, msg string) (buf string) { buf = "[" + cli.Address + "]" + cli.Name + ":" + msg return } //處理用戶連接 func HandleConn(conn net.Conn) { defer conn.Close() //獲取連接客戶端網絡地址 cliAddr := conn.RemoteAddr().String() //創建用戶結構體 cli := Client{make(chan string), cliAddr, cliAddr} onLineMap[cliAddr] = cli //新建協程,發送消息給客戶端 go WriteMessageToClient(cli, conn) //廣播某人在線 message <- MakeMsg(cli, "login") cli.C <- MakeMsg(cli, "i am here") isQuit := make(chan bool) //用戶是否主動退出 hasData := make(chan bool) //用戶是否發送過數據 //新建協程接收用戶發送信息 go func() { buf := make([]byte, 2048) for { n, err := conn.Read(buf) if n == 0 { //用戶退出 isQuit <- true fmt.Println("conn.Read err=", err) return } msg := string(buf[:n-1]) if len(msg) == 3 && msg == "who" { //發送用戶列表 conn.Write([]byte("user list:\n")) for _, data := range onLineMap { msg = data.Address + ":" + data.Name + "\n" conn.Write([]byte(msg)) } } else if len(msg) >= 8 && msg[:6] == "rename" { //修改用戶名 cli.Name = strings.Split(msg, "|")[1] onLineMap[cli.Address] = cli conn.Write([]byte("rename success\n")) } else { //轉發消息 message <- MakeMsg(cli, msg) } hasData <- true } }() for { select { case <-isQuit: delete(onLineMap, cli.Address) //用戶退出登錄,移除用戶 message <- MakeMsg(cli, "login out") return case <-hasData: case <-time.After(60 * time.Second): //用戶60秒不操作自動超時 delete(onLineMap, cli.Address) //用戶退出登錄,移除用戶 message <- MakeMsg(cli, "time out leave out") return } } } func main() { //監聽 listener, err := net.Listen("tcp", ":8000") if err != nil { fmt.Println("net.Listen err=", err) return } defer listener.Close() //新建一個協程,轉發消息 go Manager() //主協程 for { conn, err := listener.Accept() if err != nil { fmt.Println("listener.Accept err=", err) continue } go HandleConn(conn) //處理用戶連接 } }
goland 簡單聊天室服務端