最近写了一个chrome的websocket extension, server端用的是Java的Netty框架, 后来发现golang 实现websocket 非常简单,高效, 下面是例子, 简单实现了用户登录,广播,相当于聊天室!
package main
import (
"code.google.com/p/go.net/websocket"
"html/template"
"log"
"net/http"
"os"
"strings"
"time"
)
const (
listenAddr = "localhost:9527" // server address
)
var (
pwd, _ = os.Getwd()
RootTemp = template.Must(template.ParseFiles(pwd + "/chat.html"))
JSON = websocket.JSON // codec for JSON
Message = websocket.Message // codec for string, []byte
ActiveClients = make(map[ClientConn]string) // map containing clients
User = make(map[string]string)
)
// Initialize handlers and websocket handlers
func init() {
User["aaa"] = "aaa"
User["bbb"] = "bbb"
User["test"] = "test"
User["test2"] = "test2"
User["test3"] = "test3"
}
// Client connection consists of the websocket and the client ip
type ClientConn struct {
websocket *websocket.Conn
clientIP string
}
// WebSocket server to handle chat between clients
func SockServer(ws *websocket.Conn) {
var err error
var clientMessage string
// use []byte if websocket binary type is blob or arraybuffer
// var clientMessage []byte
// cleanup on server side
defer func() {
if err = ws.Close(); err != nil {
log.Println("Websocket could not be closed", err.Error())
}
}()
client := ws.Request().RemoteAddr
log.Println("Client connected:", client)
sockCli := ClientConn{ws, client}
ActiveClients[sockCli] = ""
log.Println("Number of clients connected:", len(ActiveClients))
// for loop so the websocket stays open otherwise
// it'll close after one Receieve and Send
for {
if err = Message.Receive(ws, &clientMessage); err != nil {
// If we cannot Read then the connection is closed
log.Println("Websocket Disconnected waiting", err.Error())
// remove the ws client conn from our active clients
delete(ActiveClients, sockCli)
log.Println("Number of clients still connected:", len(ActiveClients))
return
}
var msg_arr = strings.Split(clientMessage, "|")
if msg_arr[0] == "login" && len(msg_arr) == 3 {
name := msg_arr[1]
pass := msg_arr[2]
if pass == User[name] {
ActiveClients[sockCli] = name
if err = Message.Send(ws, "login|"+name); err != nil {
log.Println("Could not send message to ", client, err.Error())
}
} else {
log.Println("login faild:", clientMessage)
}
} else if msg_arr[0] == "msg" {
if ActiveClients[sockCli] != "" {
clientMessage = "msg|" + time.Now().Format("2006-01-02 15:04:05") + " " + ActiveClients[sockCli] + " Said: " + msg_arr[1]
for cs, na := range ActiveClients {
if na != "" {
if err = Message.Send(cs.websocket, clientMessage); err != nil {
log.Println("Could not send message to ", cs.clientIP, err.Error())
}
}
}
}
}
}
}
// RootHandler renders the template for the root page
func RootHandler(w http.ResponseWriter, req *http.Request) {
err := RootTemp.Execute(w, listenAddr)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func main() {
http.HandleFunc("/", RootHandler)
http.Handle("/socket", websocket.Handler(SockServer))
err := http.ListenAndServe(listenAddr, nil)
if err != nil {
panic("ListenAndServe: " + err.Error())
}
}