package main
import (
"fmt"
"io"
"net"
"runtime"
"sync"
)
//创建读写锁,在高并发时保护公共区的数据,不会出现数据混乱
var rwMutex sync.RWMutex
//创建全局的Client结构体
type Client struct {
name string //初始name与addr一样
addr string
C chan string
}
//创建全局在线用户列表
var onlineMap = make(map[string]Client)
//创建全局的message
var message = make(chan string)
//负责客户端数据通信
func handleConnect(conn net.Conn) {
defer conn.Close()
//获取客户端地址结构
cliAddr := conn.RemoteAddr().String()
//初始化客户端
cli := Client{cliAddr, cliAddr, make(chan string)}
//添加在线用户之前加写锁
rwMutex.Lock()
//添加到在线用户列表中
onlineMap[cliAddr] = cli
//添加完成,立即解锁
rwMutex.Unlock()
//启动go程读用户自己耳朵中的数据 Channel ---C
go WriteMsgToClient(cli, conn)
//组织用户上线广播消息 [ip+port]name:上线!
//msg := "[" + cliAddr + "]" + cli.name + ":" + "上线了!"
msg := makeMsg("上线!", cli)
//将上线消息写入全局message内,自动广播
message <- msg
//在用户广播自己上线后创建匿名go程获取用户聊天内容
go func() {
//读取用户发送的消息
buf := make([]byte, 4096)
for true {
read, err := conn.Read(buf) //无数据阻塞,有数据继续
if read == 0 {
fmt.Println("客户端下线")
return
}
if err != nil && err != io.EOF {
fmt.Println("read error:", err)
return
}
//fmt.Println("测试---:", buf[:read-1])
msg := string(buf[:read-1])
//组织用户聊天的内容,并写入全局message
message <- makeMsg(msg, cli)
}
}()
//添加测试代码,防止当前go程提前退出
for true {
runtime.GC()
}
}
//封装函数,组织发送的数据信息
func makeMsg(str string, cli Client) string {
return "[" + cli.addr + "]" + cli.name + ":" + str
}
func WriteMsgToClient(cli Client, conn net.Conn) {
for true {
//将自己耳朵的数据读出来写到自己客户端
msg := <-cli.C
conn.Write([]byte(msg + "\n"))
}
}
//全局的Manage go程,监听全局的message中是否有数据
func Manager() {
for {
msg := <-message
//进行读加锁操作
rwMutex.RLock()
//实时遍历在线用户列表
for _, cli := range onlineMap {
//将全局message读到的数据写入到每个用户的耳朵中channel---C
cli.C <- msg
}
rwMutex.RUnlock()
}
}
func main() {
//启动服务器,监听客户端的链接请求
listener, err := net.Listen("tcp", "127.0.0.1:8800")
if err != nil {
fmt.Println("listen error:", err)
return
}
defer listener.Close()
//创建并启动Manager管理者go程
go Manager()
for {
//服务器循环监听客户端的链接请求
conn, err := listener.Accept()
if err != nil {
fmt.Println("accept error:", err)
continue
}
//启动新go程与客户端进行数据对接
go handleConnect(conn)
}
}
golang实现聊天室
最新推荐文章于 2024-08-15 22:08:43 发布