从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)

原文发表时间:2017-01-01

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏FreeBuf

使用Python检测并绕过Web应用程序防火墙

Web应用防火墙通常会被部署在Web客户端与Web服务器之间,以过滤来自服务器的恶意流量。而作为一名渗透测试人员,想要更好的突破目标系统,就必须要了解目标系统的...

4205
来自专栏IT大咖说

饿了么资深Android工程师带你领略Kotlin协程的力量

内容来源:2018 年 6 月 28 日,饿了么资深Android工程师张涛在“droidcon上海2018安卓技术大会”进行《领略kotlin协程的力量》演讲...

5814
来自专栏为数不多的Android技巧

Android Studio你不知道的调试技巧

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

851
来自专栏Golang语言社区

Golang 之协程详解

  对于 进程、线程,都是有内核进行调度,有 CPU 时间片的概念,进行 抢占式调度(有多种调度算法)

2595
来自专栏Ryan Miao

Git 工作流的正确打开方式

前言 一直在使用git做版本控制,也一直工作很顺利,直到和别人发生冲突的时候。这才注意到git 工作流并不是那么简单。比如,之前遇到的清理历史。百度到的资料很...

3256
来自专栏流媒体人生

Yate开发向导

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

1083
来自专栏coding

Linux笔记1

2763
来自专栏编程之旅

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

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

961
来自专栏非著名程序员

Android Studio你不知道的调试技巧

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

30910
来自专栏Golang语言社区

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

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

3207

扫码关注云+社区

领取腾讯云代金券