Go 语言使用 websocket

在Google官方维护的code.google.com\p\go.net\websocket包中的server.go文件中,曾经有这么一段描述:
// Handler is a simple interface to a WebSocket browser client.
// It checks if Origin header is valid URL by default.
// You might want to verify websocket.Conn.Config().Origin in the func.
// If you use Server instead of Handler, you could call websocket.Origin and
// check the origin in your Handshake func. So, if you want to accept
// non-browser client, which doesn't send Origin header, you could use Server
//. that doesn't check origin in its Handshake.
 
这里说到,Handler是一个针对Websocket浏览器客户端的简单接口,默认情况下,Handler会检查Http请求的头文件的Origin是否是一个有效的值。最后说到,如果你想接收一个并不带有Origin字段信息的非浏览器客户端发送的websocket请求,你应该使用Server,使用Server不会在Websocket握手时对Origin进行检查。
 
也许我们会问,什么是浏览器客户端,而什么又是非浏览器客户端,笔者对此研究的不深,只是在开发中发现,在进行go web编程时,由于go本身可以使用template模板向用户推送页面,比如用户在客户端输入127.0.0.1:9000,服务器收到这个请求,就会发送网站的首页给用户(这里假设127.0.0.1:9000的/,这个路由对应一个首页的get请求)。笔者认为凡是通过web服务器推送给客户的页面返回的请求,就是浏览器客户端。而除此之外的其他的静态的网页请求,以及一些手机(andriod、ios的手机)客户端发送的请求都属于非浏览器客户端。
需要说明的是,上面这个说法是笔者个人的看法,如果有错,请指正,不必过于和我纠缠这个问题哦!(呵呵)
 
那我们又会问,如果是浏览器客户端,该如何使用Handler,而非浏览器客户端,该如何使用Server呢?下面就简单举例说一下:
先说浏览器客户端的监听websocket编程的写法,浏览器客户端使用Handler(主要看main函数的实现),代码实例为:
package main
import (
   "bufio"
   "code.google.com/p/go.net/websocket"
   "container/list"
   "fmt"
   "io"
   "net/http"
)
var connid int
var conns *list.List
func ChatroomServer(ws *websocket.Conn) {
   defer ws.Close()
   connid++
   id := connid
   fmt.Printf("connection id: %d\n", id)
   item := conns.PushBack(ws)
   conns.Remove(item)
   name := fmt.Sprintf("user%d", id)
   SendMessage(nil, fmt.Sprintf("welcome %s join\n", name))
   r := bufio.NewReader(ws)
   for {
      data, err := r.ReadBytes('\n')
      if err != nil {
          fmt.Printf("disconnected id: %d\n", id)
          SendMessage(item, fmt.Sprintf("%s offline\n", name))
          break
      }
      fmt.Printf("%s: %s", name, data)
      SendMessage(item, fmt.Sprintf("%s\t> %s", name, data))
   }
}
func SendMessage(self *list.Element, data string) {
   for item := conns.Front(); item != nil; item = item.Next() {
       ws, ok := item.Value.(*websocket.Conn)
       if !ok {
         panic("item not *websocket.Conn")
       }
       if item == self {
         continue
       }
       io.WriteString(ws, data)
   }
}
func Client(w http.ResponseWriter, r *http.Request) {
     html := "这里是一段html代码,呵呵!这个html代码中含有javascript脚本,脚本中含有创建websocket的代码,由于微博会将这段代码渲染成网页,所以暂时消除这段代码!"
     io.WriteString(w, html)
}
func main() {
    fmt.Printf(`Welcome chatroom server! `)
    connid = 0
    conns = list.New()
    http.Handle("/chatroom", websocket.Handler(ChatroomServer))
    http.HandleFunc("/", Client)
    err := http.ListenAndServe(":9090", nil)
    if err != nil {
        panic("ListenAndServe: " + err.Error())
    }
}
 
以上是一个完整的针对浏览器客户端发送websocket的服务器代码,可以看到,当用户请求路由为/时,服务器推送一个页面给用户,这个页面含有websocket套接字,然后收到这个页面的用户,就可以在这个页面是输入信息发往后台,发送时使用的就是websocket。main函数中展示了如何使用websocket.Handler.
 
下面说一下非浏览器客户端的写法,非浏览器客户端,官方文档说使用Server。下面的代码说明了如何使用Server。注意这里只修改了main函数,为了能够同时监听http请求和websocket请求,与上面不同,这里使用了多协程的方式实现,同时这里的websocket监听无须路由,所有的websocket,无论路由是多少,都将被监听到,代码如下:
func main() {
    fmt.Printf(`Welcome chatroom server! `)
    connid = 0
    conns = list.New()
    http.HandleFunc("/", Client)
     
    go func(){
        err := http.ListenAndServe(":9090", websocket.Server{websocket.Config{},nil,ChatroomServer})
       if err != nil {
            panic("ListenAndServe: " + err.Error())
       }
    }()
     err := http.ListenAndServe(":9090", nil)
     if err != nil {
            panic("ListenAndServe: " + err.Error())
     }
}
 
完结

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。