首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从websocket看go的应用

从websocket看go的应用

作者头像
李海彬
发布2018-03-23 11:43:46
6710
发布2018-03-23 11:43:46
举报
文章被收录于专栏:Golang语言社区Golang语言社区

Go是互联网时代的通用编程语言。这样它就和命令行时代的C语言、图示界面时代的C++、以及互联网早期的Java语言等有不同的侧重。它强调保持自身的精巧和独立,从而能配合现有的基础框架,也能比较容易地加入新的技术。 最近使用websocket完成了一个比较满意的设计。此处,我希望能通过一个很小的示例,展示如何使用Go,通过浏览器启动和监查远端窗口系统下的程序。重点不是系统的完备,而是要突出Go语言编程的简洁。 websocket是一种建立浏览器和服务器双向实时通信的技术,是对单向http请求响应方式的提升。我设计的系统要求能长时间显示更新一个程序的运行结果,这样直接使用http轮询的代价太高。幸运的是,我可以选择客户使用的浏览器,而Chome和Safari都己经支持websocket的了。 我们先直接看程序吧。



package main

import (
        "code.google.com/p/go.net/websocket"
        "io"
        "net/http"
        "os/exec"
        "html/template"
)

func main() {
        http.HandleFunc("/", homeHandler)
        http.Handle("/ws", websocket.Handler(wsHandler))
        http.ListenAndServe(":7224", nil)
}

func wsHandler(ws *websocket.Conn) {
        for {
                s := ""
                if e := websocket.Message.Receive(ws, &s); e != nil {
                        break
                }
                c := exec.Command("cmd", "/C", s)
                if s, e := c.StderrPipe(); e == nil {
                        go io.Copy(ws, s)
                }
                if s, e := c.StdoutPipe(); e == nil {
                        if e := c.Start(); e == nil {
                                io.Copy(ws, s)
                        }
                }
        }
        ws.Close()
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
        homeTpl.Execute(w, r.Host)
}

var homeTpl = template.Must(template.New("ws").Parse(`<html>
<textarea id=idout rows=24 cols=72></textarea><hr>
<input id=idin type=search placeholder='Enter a DOS command '
onchange='send(this.value)'></input>
<script>
        var vout=document.getElementById('idout')
        var vin =  document.getElementById('idin')
        var wscon = new WebSocket("ws://{{.}}/ws")
        wscon.onclose = function(e) {vout.value = 'websocket closed'}
        wscon.onmessage = function(e) { vout.value += e.data }
        function send(s) {
                vout.value = ""
                wscon.send(s)
        }
</script>
`))

import引进必要的函数包: websocket没有在Go标准包里,所以需要给出它所在的URL。io包我们使用了它的Copy函数完成字节的传输。http包提供了搭建网页服务器的一切资源。exec使我们可以运行操作系统提供的命令。而template此处用来处理HTML写的网页。 主函数main非常利索:注册homeHandler处理主页请求,而wsHandler处理websocket的请求,然后ListenAndServe启动服务器。 homeHandler更是简单,就是直接使用template包的Execute函数执行主机名Host的替换,使浏览器能指向正确的websocket的URL。 变量homeTpl使用template包把一个代表HTML主页的字符串Parse分析成模板,其中的{{.}}会被上述Execute时给出的r.Host替换。 而此HTML字串只是简单的描述了主页会显示一个textarea和一个input。后者用来输入待执行的操作系统命令,而前者用来显示命令执行的输出。script里是Javascript写的控制逻辑,它建立一个websocket连接,并且如果input内容改变,则使用websocket的send函数发送给服务器注册的wsHandler函数处理,而从wsHandler发送过来的字节,则通过onmessage事件处理函数接收,显示在textarea中。onclose处理函数在websocket中断时调用,而wsHandler中的Message.Receive在websocket中断或者出错时会返回错误,我们用它来结束for循环。 wsHandler中的Message.Receive会一直等待一个完整的websocket发送帧。也就是说,websocket不是基于字节的流传输,而是以帧Frame为单位的消息传输。最新的Chrome可以使用developer tool观察发送接收的每一个帧,非常方便。 从s返回的命令字符串,直接送到Command函数运行在窗口系统的命令行cmd下。我们重定向此命令的标准输出和标准错误输出,从websocket发送到浏览器,由onmessage事件处理函数显示在textarea中。注意io包的Copy函数会一直执行到输入EOF,所以第一个Copy我们用go放入后台执行,而第二个Copy会在前台执行到命令结束,才继续下一循环。 好了。使用go run webcmd.go编译执行此程序,打开Chome或者Safari浏览器,指向http://localhost:7224,在最下面的输入栏输入go,应该可以看到go命令说明,输入dir可以看到本目录的文件列表。我们再写个数羊的测试,sheep.go


package main

import "time"

func main() {
        for i := 0; ; i++ {
                time.Sleep(time.Second)
                print(i)
        }
}

在输入栏输入go run sheep.go, 就看到它每秒一个的数下去。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2016-10-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Golang语言社区 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档