Golang WebSocket实现简单的聊天系统

YXWKY · · 1688 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

本文只是一个简单的案例,如有疑问,欢迎探讨!

首先来看,为什么需要WebSocket?
再来看一类需求:一个天气预报软件,我们需要根据天气变化实时获取最新数据,如果使用平常用的http需要客户端主动的从服务端拉取,并且我们不知道服务端什么时候会产生新的数据,在这个时候我们使用http就无法很好的完成这个功能了。
因为Http协议只能由客户端发起请求,而无法由服务端主动向客户端推送数据。所以介于类似的问题,WebSocket就油然而生了。
WebSocket 协议在2008年诞生,2011年成为国际标准,现在大部分的浏览器都已经支持该协议。
Golang中使用的WebSocket有好几个,本文使用的是gorilla里面的。

  • 获取WebSocket
go get github.com/gorilla/websocket
  • 普通的Http协议到WebSocket协议要进行升级处理
upgrader := websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
        return true
    }
}
upgrader.Upgrade(w,r,nil)

每升级一次链接就表示有一个客户连接产生!
服务端代码是做为一个中转站,将客户端发过来的代码转发出去:

func main() {
    http.HandleFunc("/serveWs", serveWs)
    go handleMsg()
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        fmt.Println("ListenAndServe出错:", err.Error())
    }
}
func serveWs(w http.ResponseWriter, r *http.Request) {
    count++
    fmt.Println("新增客户端", count)
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        fmt.Println("升级ws出错:\n", err.Error())
        return
    }
    defer conn.Close()
    clients[conn] = true
    for {
        _, msg, err := conn.ReadMessage()
        if err != nil {
            fmt.Println("serveWs读取消息出错:\n", err.Error())
            break
        }
        msg_chan <- msg
        //fmt.Printf("serveWs读取到消息:%s,mt=%d\n", msg, mt)
        // err = conn.WriteMessage(mt, msg)
        // if err != nil {
        //  fmt.Println("serveWs写入消息出错:\n", err.Error())
        //  break
        // }
    }
}
func handleMsg() {
    for {
        data := <-msg_chan
        for c, _ := range clients {
            err := c.WriteMessage(websocket.TextMessage, &data)
            if err != nil {
                fmt.Println("服务端转发失败", err.Error())
                return
            }
        }
    }
}

客户端是简单的连接到服务,然后进行数据的发送。

var input string

func main() {
    interrupt := make(chan os.Signal, 1)
    signal.Notify(interrupt, os.Interrupt)

    u := url.URL{Scheme: "ws", Host: "localhost:8080", Path: "/serveWs"}
    fmt.Println("connecting to %s\n", u.String())
    c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
    if err != nil {
        fmt.Println("连接失败:", err.Error())
        return
    }
    defer c.Close()
    go func() {
        for {
            _, msg, err := c.ReadMessage()
            if err != nil {
                fmt.Println("Client接收消息失败:\n", err.Error())
                return
            }
            fmt.Printf("Client接收消息:%s\n", msg)
        }
    }()

    go func() {
        for {
            n, err := fmt.Scanln(&input)
            if err != nil {
                fmt.Println(n, "--", err.Error())
            } else {
                err = c.WriteMessage(websocket.TextMessage, []byte(input))
                if err != nil {
                    fmt.Println("client", err.Error())
                    return
                }
            }
        }
    }()
    //ticker := time.NewTicker(2 * time.Second)
    //defer ticker.Stop()
    for {
        select {
        // case <-ticker.C:
        //  err := c.WriteMessage(websocket.TextMessage, []byte("Client写入.."))
        //  if err != nil {
        //      fmt.Println("Client写入数据失败:", err.Error())
        //      return
        //  }
        case <-interrupt:
            fmt.Println("客户端interrupt")
            err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
            if err != nil {
                fmt.Println("客户端写入关闭数据失败:", err.Error())
                return
            }
        }
    }
}

本小案例还有一大堆的需要加的东西,争取下次把ping pong之类的配置加上去,共勉!


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:YXWKY

查看原文:Golang WebSocket实现简单的聊天系统

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1688 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传