此处固定是发给clients["1"]客户端消息,也就是发给自己。而且不是线程安全的!!!

package main

import (
	"github.com/gorilla/websocket"
	"net/http"
	"log"
	"fmt"
)

type Message struct {
	Msg string // 消息内容
	ToId string // 目标用户的id
	FromId string // 发送消息的用户的id
}

var clients = make(map[string] *websocket.Conn)	//连接客户端(在线的),其中map的键为用户id
var pushMsgs = make(chan Message, 1000)	//要推送的消息

// 配置upgrader
var upgrader = websocket.Upgrader{
	// 允许跨域
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func main() {
	// 创建一个简单的文件服务器
	fs := http.FileServer(http.Dir("../public"))
	http.Handle("/", fs)

	// 配置websocket路由
	http.HandleFunc("/ws", WsConns)

	// 收听传入的聊天信息
	go ToMessage()

	// 在本地主机端口上启动并记录所有错误
	log.Println("http server started on :8000")
	err := http.ListenAndServe(":8000", nil)
	if err != nil {
		log.Fatal("ListenAndServe error:", err)
	}
}

func WsConns(w http.ResponseWriter, r *http.Request) {
	//完成握手升级
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Fatal(err)
	}

	// 确保在函数返回时关闭连接
	defer ws.Close()

	// 提示下机
	defer fmt.Printf("——%v下机了——\n", ws.RemoteAddr())

	// 注册新客户端
	clients["1"] = ws

	//fmt.Println(clients["1"].)

	// 输出ip
	fmt.Println("当前登录用户:", ws.RemoteAddr())

	for {
		var msg Message
		err := ws.ReadJSON(&msg)

		if err != nil {
			log.Printf("error1: %v", err)
			// 若接收消息错误,则将该发送消息的用户的websocket连接去掉
			delete(clients, msg.FromId)
		}

		//将接收到的消息写入消息channel
		pushMsgs <- msg
	}
}

func ToMessage() {
	for {
		// 从消息推送channel获取消息
		msg := <- pushMsgs

		// 发送给指定的客户端
		err := clients["1"].WriteJSON(msg)
		if err != nil {
			log.Printf("error2: %v", err)
			clients["1"].Close()
			delete(clients, "1")
		}

	}
}