前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言实现Websocket服务端

Go语言实现Websocket服务端

作者头像
码客说
发布2024-03-29 12:52:05
860
发布2024-03-29 12:52:05
举报
文章被收录于专栏:码客码客

项目初始化

创建项目xh-control-ws

进入目录下进行初始化

代码语言:javascript
复制
go mod init xh-control-ws
go mod tidy

安装依赖

安装依赖库

代码语言:javascript
复制
go get github.com/gorilla/websocket

基本示例

创建文件main.go

代码语言:javascript
复制
package main

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

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	// 解决跨域问题
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func main() {
	http.HandleFunc("/ws", echoHandler)
	log.Fatal(http.ListenAndServe(":10088", nil))
}

func echoHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	defer conn.Close()
	// 设置关闭处理函数
	conn.SetCloseHandler(func(code int, text string) error {
		// 连接关闭时的处理逻辑
		log.Printf("Connection closed [%s]:\ncode %d and reason: %s\n", conn.RemoteAddr().String(), code, text)
		return nil
	})
	log.Printf("Connection open [%s]:\n", conn.RemoteAddr().String())
	for {
		messageType, message, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			break
		}
		if messageType == websocket.TextMessage {
			//接收消息
			log.Printf("Received [%s]:\nmessage:%s", conn.RemoteAddr().String(), message)
			//发送消息
			sendMsg := "服务器返回:" + string(message)
			err = conn.WriteMessage(messageType, []byte(sendMsg))
			log.Printf("Send [%s]:\nmessage:%s", conn.RemoteAddr().String(), sendMsg)
			if err != nil {
				log.Println(err)
				break
			}
		}
	}
}

协程发送消息

我们想到的是这样的,但是这样会报错

错误的写法:

代码语言:javascript
复制
func sendMsg(conn *websocket.Conn, msg string) {
	go func() {
		err := conn.WriteMessage(websocket.TextMessage, []byte(msg))
		if err != nil {
			return
		}
		log.Printf("Send [%s]:\nmessage:%s", conn.RemoteAddr().String(), msg)
	}()
}

正确的写法:

添加一个对象

代码语言:javascript
复制
type SendMsgModel struct {
	Conn *websocket.Conn `json:"conn"` //概要
	Msg  string          `json:"msg"`  //用户ID
}

代码中

代码语言:javascript
复制
var broadcast = make(chan model.SendMsgModel)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	// 解决跨域问题
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func main() {
	http.HandleFunc("/ws", echoHandler)
	go handleMessages()
	log.Fatal(http.ListenAndServe(":10088", nil))
}

func handleMessages() {
	for {
		// 从消息通道中读取消息
		message := <-broadcast
		err := message.Conn.WriteMessage(websocket.TextMessage, []byte(message.Msg))
		if err != nil {
			fmt.Println(err)
		}
	}
}

func sendMsg(conn *websocket.Conn, msg string) {
    // 要发送的消息放入通道中
	broadcast <- model.SendMsgModel{Conn: conn, Msg: msg}
}

如果想多个协程处理,handleMessages()调用多次即可,是不会导致处理信息重复的。

代码语言:javascript
复制
func main() {
	http.HandleFunc("/ws", echoHandler)
	go handleMessages()
    go handleMessages()
    go handleMessages()
	log.Fatal(http.ListenAndServe(":10088", nil))
}

连接相关

连接的标识

代码语言:javascript
复制
conn.RemoteAddr().String()

连接关闭的回调

代码语言:javascript
复制
// 设置关闭处理函数
conn.SetCloseHandler(func(code int, text string) error {
    // 连接关闭时的处理逻辑
    log.Printf("Connection closed [%s]:\ncode %d and reason: %s\n", conn.RemoteAddr().String(), code, text)
    return nil
})

前端测试

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WS测试</title>
</head>
<body>
<script>
    let ws = new WebSocket("ws://localhost:10088/ws");
    ws.onopen = function () {
        console.log("Connected");
        ws.send("Hello, World!");
    };

    ws.onmessage = function (event) {
        console.log("Received message: " + event.data);
    };

    ws.onclose = function () {
        console.log("Disconnected");
    };
</script>
</body>
</html>

类型转换

在Go语言中,可以使用[]bytestring类型之间进行转换。

这两种类型之间的转换可以通过类型转换或者使用标准库中的函数来完成。

[]bytestring的转换:

可以使用string()函数将[]byte转换为string

代码语言:javascript
复制
byteSlice := []byte{'H', 'e', 'l', 'l', 'o'}
str := string(byteSlice)

string[]byte的转换:

可以使用[]byte()函数将string转换为[]byte

代码语言:javascript
复制
str := "Hello"
byteSlice := []byte(str)

需要注意的是,在Go中,string是不可变的,而[]byte是可变的。

因此,将string转换为[]byte后,可以修改[]byte中的内容,但是不能直接修改string的内容。

示例:

代码语言:javascript
复制
str := "Hello"
byteSlice := []byte(str)
byteSlice[0] = 'h'
modifiedStr := string(byteSlice)
fmt.Println(modifiedStr) // 输出 "hello"

但是,直接修改string中的内容是不被允许的:

代码语言:javascript
复制
str := "Hello"
// 下面这行代码会导致编译错误,因为string的内容不可修改
// str[0] = 'h'

这些方法可以方便地在string[]byte之间进行转换。

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 项目初始化
  • 安装依赖
  • 基本示例
  • 协程发送消息
  • 连接相关
  • 前端测试
  • 类型转换
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档


http://www.vxiaotou.com