您的位置 首页 golang

第三十三章: Golang WebSocket Vue构建通信


1. 目标

  1. 使用 Golang 编写一个WebSocker 服务端
    1. 能接受客户端的WebSocket连接
    2. 启动服务器时接收命令行参数
    3. 能响应客户端数据
      1. 模式一 : webSocket 回音模式
      2. 模式二 : 图灵机器人聊天模式
  2. 使用Golang 编写一个WebSocket 客户端
  3. 使用 Vue 编写一个WebSocket 客户端
    1. 能和服务端通信
    2. 能主动获取WebSocket当前状态
    3. 能主动关闭WebSocket连接
    4. 能主动重新连接WebSokct连接
    5. 能显示WebSocket通信数据

2. 项目目录

|__common|____service_robot.go| server.go| myClient.go
common\service_robot.go

图灵机器人服务 , 提供给其他服务调用

package commonimport (    "bytes"    "encoding/json"    "errors"    "io/ioutil"    "log"    "net/http")var err errorconst (    // 你的图灵机器人 apikey    APIKEY = ""    // 你的 userId    USERID = ""    // 图灵的接口请求地址    URL    = "http://openapi.tuling123.com/openapi/api/v2")type ReqData struct {    ReqType    int                    `json:"reqType"`    Perception map[string]interface{} `json:"perception"`    UserInfo   map[string]string      `json:"userInfo"`}type Result struct {    ResultType string                 `json:"resultType"`    Values     map[string]interface{} `json:"values"`    GroupType  int                    `json:"groupType"`}type RespData struct {    Intent  map[string]interface{} `json:"intent"`    Results []Result               `json:"results"`}func NewRobot() *ReqData {    info := map[string]string{        "apiKey": APIKEY,        "userId": USERID,    }    return &ReqData{        ReqType:    0,        Perception: nil,        UserInfo:   info,    }}func (r *ReqData) Chat(v interface{}) (error, []interface{}) {    if val, ok := v.(string); ok {        inputText := map[string]string{            "text": val,        }        r.Perception = make(map[string]interface{})        r.Perception["inputText"] = inputText        jsonData, err := json.Marshal(r)        if err == nil {            return r.Post(jsonData)        }    } else {        err = errors.New("format error")    }    return err, nil}func (r *ReqData) Post(data []byte) (error, []interface{}) {    defer func() {        if err != nil {            log.Print("service_robot:post", err)        }    }()    body := bytes.NewBuffer([]byte(data))    req, err := http.NewRequest("POST", URL, body)    if err == nil {        req.Header.Add("Accept", "application/json")        req.Header.Add("Content-Type", "application/json")        resp, err := http.DefaultClient.Do(req)        defer resp.Body.Close()        if err != nil {            return err, nil        }        result, err := ioutil.ReadAll(resp.Body)        if err != nil {            return err, nil        }        log.Println(string(result))        var response RespData        err = json.Unmarshal(result, &response)        if err != nil {            return err, nil        }        var outPut []interface{}        for _, v := range response.Results {            for _, value := range v.Values {                outPut = append(outPut, value)            }        }        return nil, outPut    }    return err, nil}
server.go

WebSocket 服务端

package mainimport (    "GoNote/chapter1/ws/common"    "flag"    "github.com/gorilla/websocket"    "log"    "net/http")var modeDescribe = `webSocket response model :--echo default value--robot The Turing robot responded`var addr = flag.String("addr", "", "http service addr")var model = flag.String("model", "", modeDescribe)var upgrader = websocket.Upgrader{    CheckOrigin: func(r *http.Request) bool {        return true    },}func echoFunc(w http.ResponseWriter, r *http.Request) {    c, err := upgrader.Upgrade(w, r, nil)    if err != nil {        log.Println("upgrader :", err)        return    }    defer func() {        log.Println(c.RemoteAddr().String(), "connect close")    }()    defer c.Close()    log.Println(c.RemoteAddr().String(), "connect success")    var robot = common.NewRobot()    for {        mt, message, err := c.ReadMessage()        if err != nil {            break        }        //t := time.Now().Format("2006-01-02 15:04:05")        m := string(message)        log.Println("server receive message :", m)        // robot 机器人应答        if *model == "robot" {            err, result := robot.Chat(m)            if err == nil {                for _, k := range result {                    if s, ok := k.(string); ok {                        message = []byte(s)                        err = c.WriteMessage(mt, message)                    }                }            }        } else if *model == "echo" {            // echo 回音服务            message = []byte(m)            err = c.WriteMessage(mt, message)            if err != nil {                log.Println("write :", err)            }        }    }}func main() {    flag.Parse()    log.SetFlags(0)    log.Println("addr : ", *addr)    http.HandleFunc("/echo", echoFunc)    log.Fatal(http.ListenAndServe(*addr, nil))}
myclient.go

WebSocket 客户端

package mainimport (    "flag"    "fmt"    "github.com/gorilla/websocket"    "log"    "net/url"    "os"    "os/signal")var addr2 = flag.String("addr", "127.0.0.1:8080", "ws service addr")var key stringfunc main() {    defer func() {        if err := recover(); err != nil {            log.Println("error : ", err)        }    }()    flag.Parse()    log.SetFlags(0)    interrupt := make(chan os.Signal, 1)    signal.Notify(interrupt, os.Interrupt)    u := url.URL{        Scheme: "ws",        Host:   *addr2,        Path:   "/echo",    }    log.Printf("connecting to %s", u.String())    c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)    if err != nil {        log.Fatal("websocket connect error : ", err)    }    defer c.Close()    receiveData := make(chan string)    responseMessage := make(chan string)    go func() {        for {            fmt.Print("请输入聊天内容 : ")            fmt.Scan(&key)            if key != "" {                receiveData <- key            }            data := <-responseMessage            fmt.Println("I receive message : ", data)        }    }()    for {        select {        case <-interrupt:            log.Println("interrupt")            err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))            if err != nil {                log.Println("write close:", err)                return            }            close(receiveData)        case data := <-receiveData:            err := c.WriteMessage(websocket.TextMessage, []byte(data))            if err != nil {                log.Println("write:", err)                return            }            _, message, err := c.ReadMessage()            if err != nil {                log.Println("read from server err:", err)            } else {                responseMessage <- string(message)            }        }    }}
WebSocket 客户端测试
$ go run server.go -addr 127.0.0.1:8080 -model robotaddr :  127.0.0.1:8080127.0.0.1:52402 connect successserver receive message : 北京天气{"intent":{"actionName":"","code":10008,"intentName":"","parameters":{"date":"","city":"北京"}},"results":[{"groupType":1,"resultType":"text","values":{"text":"北京:周六 05月30日,雷阵雨 南风,最低气温18度,最高气温30度。"}}]}
$ go run myClient.goconnecting to ws://127.0.0.1:8080/echo请输入聊天内容 : 北京天气I receive message :  北京:周六 05月30日,雷阵雨 南风,最低气温18度,最高气温30度。请输入聊天内容 :
vue WebSocket 客户端

这边我们使用的 JavaScript 库是 Vue

也可以就用简单的html去实现

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Document</title>    <!-- import Vue before Element -->    <script src="https://unpkg.com/vue/dist/vue.js"></script>    <!-- import JavaScript -->    <script src="https://unpkg.com/element-ui/lib/index.js"></script>    <!-- 引入样式 -->    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"></head><body>    <div id="app">        <el-row :gutter="20">            <el-col :span="16">                <div class="grid-content bg-purple">                    <el-input v-model="message" placeholder="请输入内容" @keyup.enter.native="submitMessage"></el-input>                </div>            </el-col>            <el-col :span="8">                <div class="grid-content bg-purple">                    <el-button @click="submitMessage">发送信息</el-button>                </div>            </el-col>        </el-row>        <el-row>            <el-col :span="24">                <div class="grid-content bg-purple-dark">                    <el-button type="primary" @click="GetWsStatus">获取WS状态</el-button>                    <el-button type="success" @click="defaultWs">重新连接WS</el-button>                    <el-button type="info" @click="reloadPage">重新加载页面</el-button>                    <el-button type="warning" @click="showRespData" v-model="showButtonTitle">{{showButtonTitle}}数据</el-button>                    <el-button type="danger" @click="doCloseWS">关闭WS连接</el-button>                </div>            </el-col>        </el-row>        <el-row>            <el-col :span="24">                <div class="grid-content bg-purple-light" v-show="showSwitch && showData != ''" v-html="showData">                 </div>            </el-col>        </el-row>    </div>    <script>        new Vue({            el: '#app',            data() {                return {                    addr: '127.0.0.1',                    port: '8080',                    message: '',                    showSwitch: false,                    showData: '',                    showButtonTitle:'显示',                    ws: null                }            },            // 初始创建            created() {                this.defaultWs()            },            // 离开页面时销毁ws            destroyed() {                this.ws.close()            },            methods: {                defaultWs() {                    console.log('try to connect webSocket')                    if ("WebSocket" in window) {                        console.log('support webSocket')                        var connectInfo = 'ws://' + this.addr + ':' + this.port + '/echo'                        this.ws = new WebSocket(connectInfo)                        this.ws.onopen = this.wsOnopen                        this.ws.onmessage = this.wsOnMessage                        this.ws.onclose = this.wsOnClose                    }                },                wsOnopen() {                    console.log('connect success')                },                wsOnMessage(e) {                    console.log('receive data: ')                    this.showData += '<span style="float:right">'+ e.data + ' : say server' + '</span><br />'                    console.log(e.data)                    console.log(this.showData)                },                wsOnClose(e) {                    this.ws.close()                },                wsOnSend(data) {                    this.ws.send(data)                },                // 提交信息                submitMessage() {                    if (this.message !== '') {                        console.log('submit some data....')                        this.wsOnSend(this.message)                        this.showData += 'I say:' + this.message+'<br />'                        this.message = ''                    }                },                // ws 状态查询                GetWsStatus() {                    switch (this.ws.readyState) {                        // 正在连接                        case WebSocket.CONNECTING:                            this.$message({                                message: 'WebSocket正在连接',                            })                            break                            // 连接成功                            case WebSocket.OPEN:                            this.$message({                                message: 'WebSocket连接成功',                                type:'success'                            })                            break                            // 已经关闭                            case WebSocket.CLOSED:                            this.$message({                                message: 'WebSocket连接已经关闭',                                type: 'error'                            })                            break                            // 正在关闭                            case WebSocket.CLOSING:                            this.$message({                                message: 'WebSocket连接正在关闭',                            })                            break                    }                },                // 执行关闭ws                doCloseWS() {                    this.wsOnClose()                    this.$message({                        message: 'WebSocket关闭成功',                        type: 'success'                    });                },                // 重新加载页面                reloadPage() {                    location.reload()                },                // 显示获取的数据                showRespData() {                    this.showSwitch ? this.showButtonTitle = '显示' : this.showButtonTitle='隐藏'                    this.showSwitch ? this.showSwitch = false : this.showSwitch = true                }            },        })    </script></body><style>    .el-row {        margin-top: 10px;    }    .bg-purple-light {        background-color: aliceblue;    }    .speak-input {        height: 200px;    }    </style></html>
前端的 WebSocket 测试
websocket-vue-test.png

文章来源:智云一二三科技

文章标题:第三十三章: Golang WebSocket Vue构建通信

文章地址:https://www.zhihuclub.com/1026.shtml

关于作者: 智云科技

热门文章

网站地图