美文网首页
关于Go制作聊天功能

关于Go制作聊天功能

作者: paterL | 来源:发表于2023-07-29 22:34 被阅读0次

    采用技术,Go、channel、协程、redis、websocket
    package model

    import (
    "encoding/json"
    "fmt"
    "github.com/gorilla/websocket"
    "gorm.io/gorm"
    "net"
    "net/http"
    "strconv"
    "sync"
    )

    //消息
    type Message struct {
    gorm.Model
    FormId int64 //发送者
    TargetId int64 //接收者
    Type int //私聊、群聊、广播 消息类型
    Media int //消息类型 文字、图片、音频
    Content string //消息内容
    Pic string
    Url string
    Desc string //描述
    Amount int //数字统计
    }

    //人员关系
    type Contact struct {
    gorm.Model
    OwnerId uint //谁的关系
    TargetId uint //对应的谁
    Type int //关系类型
    Desc string //描述
    }

    //群
    type GroupBasic struct {
    gorm.Model
    Nmae string
    OwnerId uint
    Type int
    Icon string //图标
    Desc string
    }

    type Node struct {
    Conn *websocket.Conn
    DataQuene chan []byte
    //GroupSets set.Interface
    }

    //映射关系
    var clientMap map[int64]Node = make(map[int64]Node, 0)

    //读写锁
    var rwLocker sync.RWMutex

    func Chat(write http.ResponseWriter, request *http.Request) {

    //校验Token
    query := request.URL.Query()
    Id := query.Get("userId")
    //token := query.Get("token")
    //targetId := query.Get("targetId")
    userid, _ := strconv.ParseInt(Id, 10, 64)
    //context := query.Get("context")
    //msgtype := query.Get("type")
    conn, err := (&websocket.Upgrader{
        CheckOrigin: func(r *http.Request) bool {
            return true
        },
    }).Upgrade(write, request, nil)
    if err != nil {
        fmt.Println(err)
        return
    }
    //获取连接
    node := &Node{
        Conn:      conn,
        DataQuene: make(chan []byte, 50),
    }
    //用户关系
    
    //userid与node绑定,并加锁
    rwLocker.Lock()
    clientMap[userid] = node
    rwLocker.Unlock()
    
    //完成发送逻辑
    go SendProc(node)
    //完成接收逻辑
    go WriteProc(node)
    sendMsg(userid, []byte("欢迎进入"))
    

    }

    func SendProc(node *Node) {
    for {
    select {
    case data := <-node.DataQuene:
    err := node.Conn.WriteMessage(websocket.TextMessage, data)
    if err != nil {
    fmt.Println(err)
    return
    }
    }
    }
    }

    func WriteProc(node *Node) {
    for {
    _, data, err := node.Conn.ReadMessage()
    if err != nil {
    fmt.Println(err)
    return
    }
    broadMsg(data)
    fmt.Println("[ws]------", data)
    }
    }

    var udpsendChan chan []byte = make(chan []byte, 1024)

    func broadMsg(data []byte) {
    //把要发送的消息放进通道里面
    udpsendChan <- data
    }

    func init() {
    go udpSendProc()
    go udpWriteProc()
    }

    //完成数据udp的发送协程
    func udpSendProc() {
    con, err := net.DialUDP("udp", nil, &net.UDPAddr{
    IP: net.IPv4(10, 102, 0, 255),
    Port: 3000,
    })
    defer con.Close()
    if err != nil {
    fmt.Println(err)
    return
    }
    for {
    select {
    case data := <-udpsendChan:
    _, err = con.Write(data)
    if err != nil {
    fmt.Println(err)
    return
    }
    }
    }
    }

    //完成udp数据接收协程
    func udpWriteProc() {
    con, err := net.ListenUDP("udp", &net.UDPAddr{
    IP: net.IPv4zero,
    Port: 3000,
    })
    if err != nil {
    fmt.Println(err)
    return
    }
    defer con.Close()
    for {
    var buf [512]byte
    n, err := con.Read(buf[0:])
    if err != nil {
    fmt.Println(err)
    return
    }
    dispatch(buf[0:n])
    }
    }

    //后端调度逻辑处理
    func dispatch(data []byte) {
    msg := Message{}
    err := json.Unmarshal(data, &msg)
    if err != nil {
    fmt.Println(err)
    return
    }
    switch msg.Type {
    case 1: //私信
    sendMsg(msg.TargetId, data)
    //case 2://群发
    // sendGroupMsg()
    //case 3:
    // sendAllMsg()
    //case 4:

    }
    

    }
    func sendMsg(userId int64, msg []byte) {
    //上锁
    rwLocker.RLock()
    node, ok := clientMap[userId]
    //解锁
    rwLocker.RUnlock()
    if ok {
    node.DataQuene <- msg
    }
    }

    相关文章

      网友评论

          本文标题:关于Go制作聊天功能

          本文链接:https://www.haomeiwen.com/subject/ejbjpdtx.html