//功能簡介
/*
1.廣播功能, 用戶上線下線 廣播所有在線用戶 某某用戶下線
2.改名功能 輸入rename|newname 可以更改自己的暱稱
3.查看當前在線用戶功能 輸入who 可列表當前在線用戶
4.聊天功能, 任一連接成員, 發送消息, 廣播所有用戶, 類似於羣聊
5.超時自動退出
*/
package main
import (
"fmt"
"net"
"strings"
"time"
)
// 線上用戶結構體
type Client struct {
C chan string //通信,發送數據對當前用戶
Name string
Addr string
}
func clientHandler(conn net.Conn) {
defer conn.Close()
// 加入到在線用戶列表中
remoteAddr := conn.RemoteAddr().String()
client := Client{make(chan string), "phpxxo", remoteAddr}
onlieMap[remoteAddr] = client
//向當前用戶發送消息
go writeMsgToClient(client, conn)
//廣播用戶上線
message <- makeMsg(client, "login success")
conn.Write([]byte(makeMsg(client, "i am here")))
clientExit := make(chan bool)
hasData := make(chan bool)
//監聽用戶消息
go func() {
buf := make([]byte, 1024)
for {
n, err := conn.Read(buf)
if n == 0 {
clientExit <- true
fmt.Println("conn.Read err:", err)
return
}
msg := string(buf[:n-1])
if msg == "who" {
conn.Write([]byte("user list:\n"))
for _, cli := range onlieMap {
conn.Write([]byte(cli.Addr + ":" + cli.Name + "\n"))
}
} else if len(msg) >= 6 && msg[:6] == "rename" {
name := strings.Split(msg, "|")[1]
client.Name = name
onlieMap[client.Addr] = client
conn.Write([]byte("rename success\n"))
} else {
message <- makeMsg(client, msg)
}
hasData <- true
}
}()
timer := time.NewTimer(time.Second * 30)
for {
select {
case <-clientExit:
delete(onlieMap, client.Addr)
message <- makeMsg(client, "login out")
return
case <-hasData:
timer.Reset(time.Second * 30)
case <-timer.C:
delete(onlieMap, client.Addr)
message <- makeMsg(client, "time out login out")
return
}
}
}
var message chan string = make(chan string) // 轉發的消息
var onlieMap map[string]Client //在線用戶
// 組裝消息
func makeMsg(client Client, msg string) string {
return "[" + client.Addr + "]" + client.Name + ":" + msg + "\r\n"
}
// 發送消息給客戶端
func writeMsgToClient(client Client, conn net.Conn) {
for msg := range client.C {
_, err := conn.Write([]byte(msg))
if err != nil {
fmt.Println("writeMsgToClient err:", err)
}
}
}
// 廣播消息
func manage() {
onlieMap = make(map[string]Client)
for {
msg := <-message
for _, client := range onlieMap {
client.C <- msg
}
}
}
func main() {
listen, err := net.Listen("tcp", "127.0.0.1:8080")
if err != nil {
fmt.Println("listen err:", err)
return
}
defer listen.Close()
go manage() //監聽用戶消息, 轉發
for {
conn, err := listen.Accept()
if err != nil {
fmt.Println("accept err:", err)
continue
}
// 用戶處理
go clientHandler(conn)
}
}
golang實現聊天后臺服務器
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.