从websocket看go的应用

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, 就看到它每秒一个的数下去。

原文发布于微信公众号 - Golang语言社区(Golangweb)

原文发表时间:2016-03-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

从websocket看go的应用

Go是互联网时代的通用编程语言。这样它就和命令行时代的C语言、图示界面时代的C++、以及互联网早期的Java语言等有不同的侧重。它强调保持自身的精巧和独立,从而...

4198
来自专栏大前端_Web

nodejs学习一CommonJS和AMD

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/articl...

1972
来自专栏Jackson0714

不惧面试:HTTP协议(3) - Cookie

1322
来自专栏coding

Linux笔记1

2203
来自专栏非著名程序员

Android Studio你不知道的调试技巧

? 写代码不可避免有Bug,通常情况下除了日志最直接的调试手段就是debug;那么你的调试技术停留在哪一阶段呢?仅仅是下个断点单步执行吗?或者你知道 Eval...

28310
来自专栏编程之旅

Python——爬虫入门 Urllib库的使用

最近在系统的学习Python爬虫,觉得还是比较有意思的,能够干很多的事情,所以也写点文章记录一下学习过程,帮助日后回顾。

881
来自专栏大内老A

ASP.NET Core的路由[1]:注册URL模式与HttpHandler的映射关系

ASP.NET Core的路由是通过一个类型为RouterMiddleware的中间件来实现的。如果我们将最终处理HTTP请求的组件称为HttpHandler,...

1110
来自专栏流媒体人生

Yate开发向导

Yate 的设计是为了提供一个可扩展性的电话引擎,试图以最简简洁的代码,在扩展所需功能与性能、稳定性之间达到最佳平衡。

983
来自专栏Golang语言社区

深入Go语言网络库的基础实现

Go语言的出现,让我见到了一门语言把网络编程这件事情给做“正确”了,当然,除了Go语言以外,还有很多语言也把这件事情做”正确”了。我一直坚持着这样的理念——要做...

3147
来自专栏大内老A

ASP.NET Core的路由[1]:注册URL模式与HttpHandler的映射关系

ASP.NET Core的路由是通过一个类型为RouterMiddleware的中间件来实现的。如果我们将最终处理HTTP请求的组件称为HttpHandler,...

3855

扫码关注云+社区