标签:lis rename map type 数据 pack ring 连接 信息
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) //处理用户连接
}
}
标签:lis rename map type 数据 pack ring 连接 信息
原文地址:https://www.cnblogs.com/lemonzwt/p/10217190.html