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

109 lines
2.4 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"
"sync"
)
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)
// 当前连接的业务
fmt.Println(user.Name, "客户端连接建立成功")
// 用户上线, 将用户加入到OnlineMap中
server.mapLock.Lock()
server.OnlineMap[user.Name] = user
server.mapLock.Unlock()
// 广播当前用户的上线消息
server.BroadCast(user, "已上线")
// 接收客户端发送的消息
go func() {
buf := make([]byte, 4096)
for {
n, err := conn.Read(buf)
if n == 0 {
server.BroadCast(user, "下线了")
return
}
if err != nil && err != io.EOF {
fmt.Println("Conn Read err:", err)
return
}
// 提取用户的消息并去除"\n"
msg := string(buf[:n-1])
// 将得到的消息进行广播
server.BroadCast(user, msg)
}
}()
// 当前handler阻塞
select {}
}
// 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)
}
}