使用Go+WebSocket练习总结

本文章仅记录使用 Golang + Websocket 开发网页对战游戏项目时遇到的问题及解决方案。
项目地址: WebGame2
该项目目前未使用任何 GL 相关API,只是使用最简单的HTML+CSS技术完成。

开发环境

后端

前端

界面简单展示

五子棋游戏
页面切换没有记录在内,可以通过左上角登录信息观察变化。测试时已经在另一个页面登录第二个账号。

文件结构

目录结构
主要结构说明

+---- [ProjectPath]
	| ---- bin				// 打包可执行程序目录
		| ---- WebGame.exe
	| ---- db 				// 程序数据目录
		| ---- [yyyyMD] 		// 日志文件
		| ---- upload  			// 上传目录
		| ---- WebGame.db		// sqlite3 日志文件
	| ---- src				// go源文件目录
		| ---- task				// 消息推送包, 配合 WsService.sendTaskData() 使用
		| ---- games			// 游戏开发包
			| ---- wzq				// 五子棋游戏包
		| ---- ws				// websocket处理包
		| ---- main				// mainbao, 程序入口包
	|  ---- ui 				// 前端代码(angular 8)目录
	| ---- WebGame.ini 		// 配置文件

踩坑&填坑

每个连接对象保存的数据被共享了?

连接监听, http.Handle() 处理的每个 websocket.Conn 都在新协程中处理

// WsService.go
http.Handle(conf.Cfgr.Ws.Url, websocket.Handler(func(conn *websocket.Conn) {
    ch := make(chan int)
    go handleConn(conn, ch)
    <-ch
}))

原来的代码

// WsService.go
var WsClient = &wsClient{}

type wsClient struct {
  // ...
  conn *websocket.Conn
  id 	string // 每个连接唯一标识
}


http.Handle(conf.Cfgr.Ws.Url, websocket.Handler(func(conn *websocket.Conn) {
    go handleConn(conn)
}))

func handleConn(conn *websocket.Conn) {
    id, _ := uuid.NewV4() // 为每个客户端产生唯一标识
	WsClient.conn = conn
	WsClient.id = string(id)
	...
}

测试结果发现 WsClient 是一个共享的 *wsClient,后来又测试不用指针创建 var WsClient = wsClient{}任然出现相同的问题:WsClient.id只能保存最后一个值,即使是子业务对象也是一样。
实验结果表明:协程并不会重复执行&wsClient{}wsClient{}new(wsClient{})这样的代码,需要手动完成创建对象的动作:

// WsService.go
const (
    BOX_SIZE       = 9 // 格子大小
    WIN_HITS_COUNT = 5 // 胜利条件: 连线个数
)

func handleConn(conn *websocket.Conn, ch chan int) {
    ws := &wsClient{} // 这里必须使用新的对象
	// ...
    ws.gameWzq = new(wzq.GameWzq) // 每个子游戏服务必须使用各自的对象(除非该服务没有保存状态)
	// ...
}

同时由于这个特性,正好可以用在游戏房间管理上:

// games/wzq/roomMgr.go
var RoomMgr = &mgr{
    games: make(map[int]*gameA),
}

// 管理类
type mgr struct {
    mu    sync.Mutex
    games map[int]*gameA // 所有五子棋游戏
}

// 五子棋游戏
type gameA struct {
    rooms map[int]*room // 所有房间
}

// 游戏房间
type room struct {
    No        int           `json:"no"`
    P1        model.Account `json:"p1"`
    P2        model.Account `json:"p2"`
    playingId int           // 可落子玩家
    stones    [BOX_SIZE][BOX_SIZE]int
}

至此问题得到解决。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Golang中的Gin框架提供了一种简单而强大的方法来构建Web应用程序。与此同时,Golang标准库中的"net/http"包提供了构建WebSocket服务器和客户端的功能。 首先,我们来看一下如何使用Gin和WebSocket构建WebSocket服务器。首先,需要导入相关的包: ```go import ( "github.com/gin-gonic/gin" "github.com/gorilla/websocket" ) ``` 接下来,在Gin中创建一个WebSocket处理函数: ```go func WebSocketHandler(c *gin.Context) { upgrader := websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, } conn, err := upgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } for { messageType, message, err := conn.ReadMessage() if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } err = conn.WriteMessage(messageType, message) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } } } ``` 上面的代码创建了一个基本的WebSocket处理函数。它使用WebSocket标准库中的Upgrader结构来处理升级连接并创建一个WebSocket连接。 然后,我们需要在Gin中设置路由来处理WebSocket请求: ```go router := gin.Default() router.GET("/ws", WebSocketHandler) ``` 以上代码将在根路径下创建一个WebSocket处理函数。 接下来,我们来看一下如何使用Golang和Gin构建WebSocket客户端。首先,我们需要导入所需的包: ```go import ( "github.com/gorilla/websocket" "net/http" ) ``` 然后,我们可以使用以下代码来创建一个WebSocket客户端: ```go func main() { c, _, err := websocket.DefaultDialer.Dial("ws://localhost:8080/ws", nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() done := make(chan struct{}) go func() { defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } log.Printf("recv: %s", message) } }() ticker := time.NewTicker(time.Second) defer ticker.Stop() for { select { case <-done: return case <-ticker.C: err := c.WriteMessage(websocket.TextMessage, []byte("Hello, Server!")) if err != nil { log.Println("write:", err) return } } } } ``` 上面的代码创建了一个WebSocket客户端,它使用WebSocket标准库中的`DefaultDialer`结构来建立WebSocket连接。 以上就是使用Golang Gin和WebSocket构建WebSocket客户端和服务器的简单示例。这些代码可以帮助我们使用Gin和Golang的标准库来构建强大的Web应用程序,并处理WebSocket通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值