go_study/bilibili/aceld/IM-System/server.go

127 lines
2.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"fmt"
"io"
"net"
"runtime"
"sync"
"time"
)
type Server struct {
Ip string
Port int
OnlineMap map[string]*User // 在线用户列表
mapLock sync.RWMutex // OnlineMap读写锁
Message chan string // 全部用户的消息管道
}
// 创建一个server的接口
func NewServer(ip string, port int) *Server {
server := &Server{
Ip: ip,
Port: port,
OnlineMap: make(map[string]*User),
Message: make(chan string),
}
return server
}
// server类的成员方法监听Message广播消息channel的goroutine, 一旦有消息就发送给全部的在线User
func (server *Server) ListenMessage() {
for {
msg := <-server.Message
// 将msg发送给全部的在线User
server.mapLock.Lock()
for _, cli := range server.OnlineMap {
cli.C <- msg
}
server.mapLock.Unlock()
}
}
// server类的成员方法向所有在线客户端发送广播
func (server *Server) BroadCast(user *User, msg string) {
sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msg
server.Message <- sendMsg
}
// server类的成员方法处理客户端连接
func (server *Server) Handler(conn net.Conn) {
user := NewUser(conn, server)
// 当前连接的业务
fmt.Println(user.Name, "客户端连接建立成功")
// 用户上线, 将用户加入到OnlineMap中
user.Online()
// 监听用户是否活跃的channel
isLive := make(chan bool)
// 接收客户端发送的消息
go func() {
buf := make([]byte, 4096)
for {
n, err := conn.Read(buf)
if n == 0 {
user.Offline()
return
}
if err != nil && err != io.EOF {
fmt.Println("Conn Read err:", err)
return
}
// 提取用户的消息并去除"\n"
msg := string(buf[:n-1])
// 将得到的消息进行广播
user.DoMessage(msg)
// 用户的任意消息代表当前用户是一个活跃的将true发给isLive管道
isLive <- true
}
}()
// 设定定时器实现超时强踢
for {
select {
case <-isLive:
// 当前用户是活跃的,应该重置定时器
// 不做任何事情为了激活select更新下面的定时器
// 只要执行time.After即实现重置定时器
case <-time.After(time.Second * 3600):
// 已经超时将当前User强制关闭
user.SendMsg("你被踢了")
// 销毁用户的资源
close(user.C)
// 关闭连接
conn.Close()
// 退出
runtime.Goexit() // return
}
}
}
// Server类的成员方法启动服务器的接口
func (server *Server) Start() {
// socket listen
listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", server.Ip, server.Port))
if err != nil {
fmt.Println("net.Listen err: ", err)
}
// close listen socket
defer listener.Close()
// 启动监听Message的goroutine
go server.ListenMessage()
// 死循环实现监听
for {
// accept
conn, err := listener.Accept()
if err != nil {
fmt.Println("listener accept err:", err)
continue
}
// do handler
go server.Handler(conn)
}
}