golang高可用IM即时通讯方案-协程发送、udp转发

1,完整代码如下

package main

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

type Node struct {
	Conn      *websocket.Conn //连接
	Addr      string          //客户端地址
	DataQueue chan []byte     //消息
	UserId    string
	TagId     string
}

var clients = make(map[*websocket.Conn]bool)
var broadcast = make(chan Message)
var upgrader = websocket.Upgrader{}
var userId int
var tagId int

type Message struct {
	Content    string `json:"content"` //消息内容
	UserId     int    `json:"userId"`
	TagUserId  int    `json:"tagUserId"`
	Type       int    `json:"type"`       //发送类型  1私聊  2群聊  3心跳
	Media      int    `json:"media"`      //消息类型  1文字 2表情包 3语音 4图片 /表情包
	CreateTime uint64 `json:"createTime"` //创建时间
	ReadTime   uint64 `json:"readTime"`   //读取时间
}

func main() {
	http.HandleFunc("/ws", handleWebSocket)

	log.Println("WebSocket server started on localhost:8000")
	err := http.ListenAndServe(":8000", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

// 读写锁
var rwLocker sync.RWMutex

// 映射关系
var clientMapsss map[string]*Node = make(map[string]*Node, 0)

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	userId := query.Get("userId")

	//userId, _ = strconv.Atoi(get)
	fmt.Println("userId >>>>>>>", userId)
	//
	//tagId := query.Get("tagId")
	tagId, _ = strconv.Atoi(getTagId)
	//fmt.Println("tagId >>>>>>>", tagId)

	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}
	node := &Node{
		Conn:      conn,
		Addr:      conn.RemoteAddr().String(), //客户端地址
		DataQueue: make(chan []byte, 50),
	}
	//go handleMessages(node)

	//clients[conn] = true

	//4. userid 跟 node绑定 并加锁
	rwLocker.Lock()
	clientMapsss[userId] = node
	rwLocker.Unlock()
	go sendProc(node)

	go recvProc(node)
	//for {
	//	var msg Message
	//	err := conn.ReadJSON(&msg)
	//	if err != nil {
	//		log.Println(err)
	//		delete(clients, conn)
	//		break
	//	}
	//
	//	broadcast <- msg
	//}

	//conn.Close()
}

func sendProc(node *Node) {
	for {
		select {
		case msgsss := <-node.DataQueue:
			fmt.Println(msgsss)
			//for i := range clientMapsss {
			fmt.Println("sendsendsendsden")
			//fmt.Println(clientMapsss[i].UserId)
			//fmt.Println(clientMapsss[i].TagId)
			fmt.Println("node.TagId", node.TagId)
			fmt.Println("node.UserId", node.UserId)
			node.Conn.WriteJSON(msgsss)
			//err := node.Conn.WriteMessage(websocket.TextMessage, data)
			//if err != nil {
			//	fmt.Println(err)
			//	return
			//}
		}
	}
}

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

func broadMsg(data []byte) {
	udpsendChan <- data
}

func init() {
	go udpSendProc()
	go udpRecvProc()
	fmt.Println("init goroutine ")
}

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

}

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

func recvProc(node *Node) {
	for {
		_, data, err := node.Conn.ReadMessage()
		if err != nil {
			fmt.Println(err)
			return
		}
		msg := Message{}
		err = json.Unmarshal(data, &msg)
		if err != nil {
			fmt.Println(err)
		}
		fmt.Println("recvProcrecvproc")
		fmt.Println(node.UserId)
		fmt.Println(node.TagId)
		fmt.Println(">>>>>>>", msg)
		//node.Conn.WriteJSON(msg)

		//node.Conn.WriteJSON()
		//心跳检测 msg.Media == -1 || msg.Type == 3
		if msg.Type == 3 {
			currentTime := uint64(time.Now().Unix())
			fmt.Println(currentTime)
			//node.Heartbeat(currentTime)
		} else {
			//dispatch(data) //分发消息存储
			broadMsg(data) //todo 将消息广播到局域网
			fmt.Println("[ws] recvProc <<<<< ", string(data))
		}
		//node.Conn.Close()
	}
}

// 后端调度逻辑处理
func dispatch(data []byte) {
	msg := Message{}
	msg.CreateTime = uint64(time.Now().Unix())
	err := json.Unmarshal(data, &msg)
	if err != nil {
		fmt.Println(err)
		return
	}
	switch msg.Type {
	case 1: //私信
		fmt.Println("dispatch  data :", string(data))
		sendMsg(msg.TagUserId, data)
	case 2: //群发
		//sendGroupMsg(msg.TargetId, data) //发送的群ID ,消息内容
		// case 4: // 心跳
		// 	node.Heartbeat()
		//case 4:
		//
	}
}

func sendMsg(tagUserId int, msg []byte) {

	rwLocker.RLock()
	node := clientMapsss[strconv.FormatInt(int64(tagUserId), 10)]
	rwLocker.RUnlock()

	jsonMsg := Message{}
	err2 := json.Unmarshal(msg, &jsonMsg)
	if err2 != nil {
		return
	}
	err := node.Conn.WriteJSON(jsonMsg)
	if err != nil {
		return
	}
	//node.DataQueue <- msg
	//r, err := utils.Red.Get(ctx, "online_"+userIdStr).Result()
	//if err != nil {
	//	fmt.Println(err)
	//}
	//if r != "" {
	//	if ok {
	//		fmt.Println("sendMsg >>> userID: ", userId, "  msg:", string(msg))
	//		node.DataQueue <- msg
	//	}
	//}
	//var key string
	//if userId > jsonMsg.UserId {
	//	key = "msg_" + userIdStr + "_" + targetIdStr
	//} else {
	//	key = "msg_" + targetIdStr + "_" + userIdStr
	//}
	//res, err := utils.Red.ZRevRange(ctx, key, 0, -1).Result()
	//if err != nil {
	//	fmt.Println(err)
	//}
	//score := float64(cap(res)) + 1
	//ress, e := utils.Red.ZAdd(ctx, key, &redis.Z{score, msg}).Result() //jsonMsg
	res, e := utils.Red.Do(ctx, "zadd", key, 1, jsonMsg).Result() //备用 后续拓展 记录完整msg
	//if e != nil {
	//	fmt.Println(e)
	//}
	//fmt.Println(ress)
}

2,请求示例,集成了udp转发,后端调度省略。。。。
2,1发送者
在这里插入图片描述
2.2接收者
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值