GoLang 即时通讯系统(一)
基础Server的构建
- 目录结构
- server
type Server struct {
Ip string
Port int
}
func NewServer(ip string, port int) *Server {
return &Server{
Ip: ip,
Port: port,
}
}
func (s *Server) handler(conn *net.TCPConn) {
fmt.Println("[Server] Connection Connect Success!!!", conn.RemoteAddr().String())
}
func (s *Server) Start() {
addr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", s.Ip, s.Port))
if err != nil {
fmt.Println(err)
return
}
listener, err := net.ListenTCP("tcp4", addr)
if err != nil {
fmt.Println("[Error] ListenTCP Error: ", err)
return
}
defer listener.Close()
fmt.Println("[Server] Start Success!!!")
for true {
conn, err := listener.AcceptTCP()
if err != nil {
fmt.Println("[Error] AcceptTCP Error: ", err)
continue
}
go s.handler(conn)
}
}
- main
func main() {
s := NewServer("127.0.0.1", 8080)
s.Start()
}
用户上线,并广播消息
- 当有用户上线时,需要封装user类,对上线的conn进行封装
- server需要管理所有上线的user
- server需要对上线的user进行广播
将上线的conn封装为user对象
将user对象添加到字典中进行管理
广播玩家上线的消息
func (s *Server) handler(conn *net.TCPConn) {
fmt.Println("[Server] Connection Connect Success!!!", conn.RemoteAddr().String())
user := NewUser(conn)
s.onlineLock.Lock()
s.OnlineMap[user.Name] = user
s.onlineLock.Unlock()
s.BroadCastMsg(user, "已上线")
select {}
}
向管道中传递要广播的上线消息
开启一个Goroutine,用来处理广播的消息
func (s *Server) ListenMsg() {
for true {
msg := <-s.MessageChan
s.onlineLock.Lock()
for _, user := range s.OnlineMap {
user.C <- msg
}
s.onlineLock.Unlock()
}
}
- 在user类中,也有一个管道来处理消息,也会单独的开启Goroutine来处理消息
- 当有消息写入管道中,管道会读取消息并发送给对端
type User struct {
Name string
Addr string
C chan string
Conn *net.TCPConn
}
func NewUser(conn *net.TCPConn) *User {
userAddr := conn.RemoteAddr().String()
user := &User{
Name: userAddr,
Addr: userAddr,
C: make(chan string),
Conn: conn,
}
go user.ListenMsg()
return user
}
func (u *User) ListenMsg() {
for true {
msg := <-u.C
u.Conn.Write([]byte(msg))
}
}
测试
func TestV2(t *testing.T) {
conn, err := net.Dial("tcp4", "127.0.0.1:8080")
if err != nil {
fmt.Println(err)
return
}
go func() {
buffer := make([]byte, 1024)
for true {
count, err := conn.Read(buffer)
if err != nil {
fmt.Println(err)
continue
}
fmt.Println(string(buffer[:count]))
}
}()
select {}
}