package main
import (
"encoding/json"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
"net/http"
"github.com/gorilla/websocket"
)
type ClientManager struct {
Clients map[*Client]bool
Broadcast chan []byte
Register chan *Client
Unregister chan *Client
}
type Client struct {
ID string
Socket *websocket.Conn
Send chan []byte
}
type Message struct {
Sender string `json:"sender,omitempty"`
Recipient string `json:"recipient,omitempty"`
Content string `json:"content,omitempty"`
}
var Manager = ClientManager{
Broadcast: make(chan []byte),
Register: make(chan *Client),
Unregister: make(chan *Client),
Clients: make(map[*Client]bool),
}
func (manager *ClientManager) Start() {
for {
select {
case conn := <-manager.Register:
manager.Clients[conn] = true
jsonMessage, _ := json.Marshal(&Message{Content: "/A new socket has connected."})
manager.Send(jsonMessage, conn)
case conn := <-manager.Unregister:
if _, ok := manager.Clients[conn]; ok {
close(conn.Send)
delete(manager.Clients, conn)
jsonMessage, _ := json.Marshal(&Message{Content: "/A socket has disconnected."})
manager.Send(jsonMessage, conn)
}
case message := <-manager.Broadcast:
for conn := range manager.Clients {
select {
case conn.Send <- message:
default:
close(conn.Send)
delete(manager.Clients, conn)
}
}
}
}
}
func (manager *ClientManager) Send(message []byte, ignore *Client) {
for conn := range manager.Clients {
if conn != ignore {
conn.Send <- message
}
}
}
func (c *Client) Read() {
defer func() {
Manager.Unregister <- c
c.Socket.Close()
}()
for {
_, message, err := c.Socket.ReadMessage()
if err != nil {
Manager.Unregister <- c
c.Socket.Close()
break
}
jsonMessage, _ := json.Marshal(&Message{Sender: c.ID, Content: string(message)})
Manager.Broadcast <- jsonMessage
}
}
func (c *Client) Write() {
defer func() {
c.Socket.Close()
}()
for {
select {
case message, ok := <-c.Send:
if !ok {
c.Socket.WriteMessage(websocket.CloseMessage, []byte{})
return
}
c.Socket.WriteMessage(websocket.TextMessage, message)
}
}
}
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
conn, error := (&websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}).Upgrade(c.Writer, c.Request, nil)
if error != nil {
http.NotFound(c.Writer, c.Request)
return
}
client := &Client{ID: uuid.NewV4().String(), Socket: conn, Send: make(chan []byte)}
Manager.Register <- client
go client.Read()
go client.Write()
})
r.Run()
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)