【golang实现即时通讯系统】(一)

发布时间 2023-03-25 16:21:07作者: Weber·Bon

即时通讯系统

1.基础server构建

  1. 创建一个Server的结构体,结构体应该包含服务端的IP和端口
  2. 写一个创建Server的方法
  3. 创建一个启动Server函数
  4. 创建一个业务链接函数

server.go

package main
import (
	"fmt"
	"net"
)

type Server struct{
    Ip string
   Port int
}
//创建Server对象
func NewServer(ip string,port int)*Server{
    server:=&Server{
        Ip:ip,
        Port:port,
    }
    return server
}
//启动Server服务函数
func(this *Server)Start(){
    listener,err:=net.Listen("tcp",fmt.Sprintf("%s:%d",this.Ip,this.Port))
    if err!=nil{
        fmt.Plrintln("Accept Error:",err)
        return
    }
    for{
         conn,err:=listener.Accept()
        if err!=nil{
            fmt.Println("Listener Accept err:",err)
            continue
        }
        go this.Handler(conn)
    }
  //Handler函数 业务函数
    func (this *Server)Handler(conn net.Conn){
        fmt.Println("业务链接成功!")
    }
}

main.go

package main

func main(){
    server:=NewServer("127.0.0.1",8888)
    server.Start()
}

2.用户上线及广播功能

  1. user.go
    1. 创建User结构体
    2. 创建User对象
    3. 监听User对应channel消息
  2. server.go
    1. Server结构体新增在线用户表和Message管道属性
    2. 在处理客户端上线的Handler函数中根据端口创建用户并添加到在线用户表中
    3. Handler函数中添加广播消息函数,广播用户上线的消息
    4. 添加广播消息的函数
    5. 添加广播消息channel方法
    6. 用一个goroutine单独监听Message管道

user.go

package main
import "net"
type User struct{
    Name string 
    Addr string
    C chan string
    conn net.Conn
}

//创建User对象
func NewUser(conn net.Conn)*User{
    userAddr:=conn.RemoteAddr().String()
    user:=&User{
        Name:userAddr,
        Addr:userAddr,
        C :make(chan string),
        conn:conn
    }
    
    //监听当前user的channel消息
    go user.ListenMessage()
    return user
}
//监听当前用户channel管道消息函数,一旦有消息,就直接发送给对端客户端
func (this *User)ListenMessage(){
    for {
        msg:=<-this.C
        this.conn.Write([]byte(msg+"\n"))
    }
}

server.go

package main

type Server struct {
    Ip string
    Port int
    Message chan string 
    OnlineMap map[string]*User
    mapLock sync.RWMutex
}
//创建一个Server对象
func NewServer(ip string ,port int)*Server{
    server:=&Server{
        Ip:ip,
        Port:port,
        Message:make(chan string),
        OnlineMap:make(map[string]*User)
    }
    return server
}
//创建启动函数
func (this *Server)Start(){
    listener,err:=net.Listen("tcp",fmt.Sprintf("%s:%d",this.IP,this.Port))
    if err!=nil{
        fmt.Println("net.Listen err:",err)
        return
    }
    defer listener.Close()
    go this.ListenMessager()
    for {
        conn,err:=listener.Accept()
         if err!=nil{
        fmt.Println("Listenner accept err:",err)
        continue
    	}
        go this.Handler(conn)
    }
}
//创建Handler函数
func (this *Server)Handler(conn net.Conn){
    user:=NewUser(conn)
    this.mapLock.Lock()
    this.OnlineMap[user.Name]=user
    this.mapLock.Unlock()
    //广播当前用户上线的消息
    this.BroadCast(user,"已上线")
    //阻塞当前handler
    select{}
}
//监听Message广播消息channel的goroutine,一旦有消息就发送给全部的在线User
func (this *Server)ListenMessager(){
    msg:=<-this.Message
    this.mapLock.Lock()
    for _,cli:=range OnlineMap{
        cli.C<-msg
    }
    this.mapLock.Unlock()
}
//广播函数
func (this *Server)BroadCast(user *User,msg string){
    sendMsg:="["+user.Addr+"]"+user.name+":"+msg
    this.Message<-sendMsg
}