golang websocket 服务端的实现

yizhihongxing

下面是关于"golang websocket 服务端的实现"的攻略。

准备工作

首先,我们需要在Go中引入websocket包,可以通过如下方式:

import "github.com/gorilla/websocket"

同时,我们还需要处理websocket的请求,这样才能确保服务端收到请求并进行处理,可以使用http.HandleFunc方法处理:

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    // 方法实现
})

建立连接

接下来,我们需要建立websocket连接,这可以通过websocket包中的Upgrade方法实现:

conn, err := upgrader.Upgrade(w, r, nil)

其中upgrader是一个配置结构体,可以设置一些参数,比如允许跨域:

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool { return true },
}

读写数据

在完成websocket连接后,我们可以开始进行数据的读写操作。首先,我们需要定义一个循环来不断读取客户端发送的消息,可以用以下代码实现:

for {
    // 读取客户端发送的消息
    messageType, p, err := conn.ReadMessage()
    if err != nil {
        log.Println(err)
        return
    }

    // 将消息发送给所有客户端
    err = conn.WriteMessage(messageType, p)
    if err != nil {
        log.Println(err)
        return
    }
}

在代码中,我们使用ReadMessage()方法读取客户端发送的消息,然后再使用WriteMessage()方法将消息发送给所有客户端。其中,messageType代表消息类型,可以是TextMessageBinaryMessagep代表消息内容。

示例1:广播聊天室

以下是一个简单的基于Golang实现的websocket广播聊天室的示例:

package main

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

var clients = make(map[*websocket.Conn]bool) // 连接客户端
var broadcast = make(chan Message)           // 广播消息

// 配置WebSocket参数
var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

// 定义Message结构体
type Message struct {
    Email    string `json:"email"`
    Username string `json:"username"`
    Message  string `json:"message"`
}

func main() {
    // 处理静态资源请求
    http.Handle("/", http.FileServer(http.Dir("./public")))

    // 处理WebSocket请求
    http.HandleFunc("/ws", handleConnections)

    // 启动goroutine监听广播消息
    go handleMessages()

    // 启动服务器
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

func handleConnections(w http.ResponseWriter, r *http.Request) {
    // 将HTTP连接升级为WebSocket连接
    ws, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Fatal(err)
    }

    // 关闭WebSocket连接
    defer ws.Close()

    // 将新连接添加到连接列表中
    clients[ws] = true

    for {
        // 读取WebSocket数据
        var msg Message
        err := ws.ReadJSON(&msg)
        if err != nil {
            log.Printf("error: %v", err)
            delete(clients, ws)
            break
        }

        // 将接收到的消息发送给广播通道
        broadcast <- msg
    }
}

func handleMessages() {
    for {
        // 从广播通道中获取消息
        msg := <-broadcast

        // 将消息发送给所有连接
        for client := range clients {
            err := client.WriteJSON(msg)
            if err != nil {
                log.Printf("error: %v", err)
                client.Close()
                delete(clients, client)
            }
        }
    }
}

这个示例中,我们使用map类型来保存所有连接的客户端,并在处理WebSocket连接时添加连接。另外,我们使用一个无缓冲通道来进行广播。

handleConnections函数中,我们使用ws.ReadJSON(&msg)方法读取客户端发送的消息,然后将消息发送给广播通道。

handleMessages函数中,我们不断从广播通道中获取消息,并使用client.WriteJSON()方法将消息发送给所有连接的客户端。

示例2:广播计数器

以下是一个简单的基于Golang实现的WebSocket计数器示例:

package main

import (
    "errors"
    "fmt"
    "net/http"
    "time"

    "github.com/gorilla/websocket"
)

// 使用websocket库升级连接
var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

// 定义连接对象
type wsConnection struct {
    wsSocket *websocket.Conn // 底层websocket
    inChan   chan []byte     // 发送队列
    outChan  chan []byte     // 接收队列
    closeChan  chan byte      // 关闭通道
    isClosed bool            // 连接是否已关闭
    mutex    sync.Mutex      // 避免重入锁
}

// 创建连接
func wsHandler(w http.ResponseWriter, r *http.Request) {
    var (
        wsConn *websocket.Conn
        err    error
        conn   *wsConnection
    )

    // 应答客户端告知websocket连接建立
    if wsConn, err = upgrader.Upgrade(w, r, w.Header()); err != nil {
        return
    }
    conn = &wsConnection{
        wsSocket: wsConn,
        inChan:   make(chan []byte, 1000),
        outChan:  make(chan []byte, 1000),
        closeChan:  make(chan byte),
        isClosed: false,
    }

    // 启动处理协程
    go conn.readLoop()
    go conn.writeLoop()

    return
}

// 处理数据读逻辑
func (wsConn *wsConnection) readLoop() {
    var (
        data []byte
        err  error
    )

    for {
        //websocket.TextMessage
        if _, data, err = wsConn.wsSocket.ReadMessage(); err != nil {
            goto ERR
        }

        select {
        case wsConn.inChan <- data:
        case <-wsConn.closeChan:
            goto CLOSED
        }
    }

ERR:
    wsConn.Close()

CLOSED:
}

// 处理数据写逻辑
func (wsConn *wsConnection) writeLoop() {
    var (
        data []byte
        err  error
    )

    for {
        select {
        case data = <-wsConn.outChan:
        case <-wsConn.closeChan:
            goto CLOSED
        }
        // 从channel中读取数据
        if err = wsConn.wsSocket.WriteMessage(websocket.TextMessage, data); err != nil {
            goto ERR
        }
    }
ERR:
    wsConn.Close()
CLOSED:
}

// 发送文本消息
func (wsConn *wsConnection) wsWriteTextMessage(message []byte) (err error) {
    select {
    case wsConn.outChan <- message:
    default:
        wsConn.wsSocket.Close()
        err = errors.New("websocket closed")
    }

    return
}

// 关闭连接
func (wsConn *wsConnection) Close() {
    wsConn.wsSocket.Close()
    wsConn.mutex.Lock()
if !wsConn.isClosed{
close(wsConn.closeChan)
wsConn.isClosed = true
}
    wsConn.mutex.Unlock()
}

func main() {
    // 注册路由和处理函数
    http.HandleFunc("/ws", wsHandler)

    // 监听端口
    http.ListenAndServe(":9090", nil)
}

在这个示例中,我们定义了一个wsConnection结构体表示连接对象,同时维护了发送队列inChan,接收队列outChan和关闭通道closeChan

wsHandler函数中,我们使用upgrader.Upgrade()方法升级连接,然后创建一个wsConnection连接对象,并启动一个读协程和一个写协程。

readLoop函数中,我们不断循环获取客户端发送的数据,并使用inChan通道将数据放入发送队列。

writeLoop函数中,我们不断循环从接收队列中获取数据,并使用wsConn.wsSocket.WriteMessage()方法将数据发送给客户端。

wsWriteTextMessage函数中,我们使用一条select语句将数据放入发送队列,如果队列已满则关闭连接。

Close函数中,我们使用Mutex避免重入锁,防止closeChan关闭多次,同时将isClosed标志设为true,表示连接已关闭。

这就是一个基本的WebSocket计数器示例。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:golang websocket 服务端的实现 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • Python面向对象之继承原理与用法案例分析

    Python面向对象之继承原理与用法案例分析 Python是一种面向对象的编程语言,在Python中,面向对象编程的继承是其核心概念之一。通过继承,我们可以实现代码重用和代码的无侵入性修改,同时也能提高程序的可维护性。本篇攻略将会深入讲解Python中的继承原理与用法,并提供常用的继承案例供参考。 继承的原理 在Python中,继承是通过创建一个新的类,并将…

    other 2023年6月26日
    00
  • json-如何在neo4j中导入json数据

    以下是在Neo4j中导入JSON数据的完整攻略: 1. Neo4j概述 Neo4j是一款高性能的图形数据库支持存储和处理大规模的图形数据。Neo4j使用Cypher查询语言来查询和操作数据,支持多种数据导入方式,包括CSV、JSON、XML等。 2. 导入JSON数据 在Neo4j中,我们可以使用以下步骤导入JSON数据: 准备JSON数据文件,例如.jso…

    other 2023年5月8日
    00
  • foxmail邮箱如何设置邮件优先级?foxmail设置邮件优先级教程

    Foxmail邮箱如何设置邮件优先级 1. 打开Foxmail邮箱设置界面 首先,打开Foxmail邮箱。点击顶部菜单栏中的“工具”,然后选择“选项”。 2. 进入邮件设置 在弹出的选项窗口中,选择“邮箱”选项卡。在该选项卡下,可以进行一系列的邮件相关设置。 3. 设置邮件优先级 在邮件设置界面中,找到“发送邮件时设置优先级”一栏。通过下拉菜单,选择你想要的…

    other 2023年6月28日
    00
  • 【hyperscan】编译hyperscan 4.0.0

    【hyperscan】编译hyperscan 4.0.0 在编写高效的网络安全应用程序时,使用快速而精确的模式匹配算法是非常重要的。Hyperscan是一款支持使用正则表达式进行高性能扫描的工具包,可以在包括x86、x64和ARM在内的多种平台上运行。在本文中,我们将介绍如何编译最新版本的Hyperscan(4.0.0)。 准备工作 在开始编译之前,需要进行…

    其他 2023年3月28日
    00
  • 使用microsoftsynctoy文件同步/备份自动化处理

    以下是使用Microsoft SyncToy文件同步/备份自动化处理的攻略,包含两个示例: 什么是Microsoft SyncToy? Microsoft SyncToy是一个免费的Windows实用程序,可用于自动化处理文件同步备。它可以帮助您快速、轻松地将文件从一个位置复制到另一个位置,或者将文件备份到外部硬盘或网络动器。 如何使用 SyncToy进行文…

    other 2023年5月6日
    00
  • linux磁盘之lsblk命令

    当然,我很乐意为您提供有关“linux磁盘之lsblk命令”的完整攻略。以下是详细的步骤和两个示例: 1. 什么是lsblk命令? lsblk命令是一个用于列出系统中所有块设备的命令。块设备是指可以被分区并用于存储数据的设备,例如硬盘、SSD、USB驱动器等。lsblk命令可以显示每个块设备的名称、大小、挂载点等信息。 以下是lsblk命令的基本语法: ls…

    other 2023年5月6日
    00
  • Android Studio 下 Flutter 开发环境搭建过程

    下面我为你详细讲解“Android Studio 下 Flutter 开发环境搭建过程”的完整攻略: 1. 确认前置条件 在安装 Flutter 并使用 Android Studio 进行开发之前,你需要确认几个前置条件是否都已经满足了,这些前置条件包括: 确认你的电脑系统是否符合 Flutter 的要求,Flutter 可以运行在以下系统上:Windows…

    other 2023年6月27日
    00
  • iQOO 11 Pro开发者模式在哪?iQOO 11 Pro进入开发者模式的方法

    针对“iQOO 11 Pro开发者模式在哪? iQOO 11 Pro进入开发者模式的方法”的问题,下面是针对此问题的攻略。 1. 什么是iQOO 11 Pro开发者模式? iQOO 11 Pro开发者模式是安卓手机里一个专门为开发者服务的调试选项,可以帮助开发者进行系统调试、USB调试、性能调试和网络调试等工作,具有诸多特别的功能,但需要注意的是系统代码较默…

    other 2023年6月26日
    00
合作推广
合作推广
分享本页
返回顶部