WebSocketをGoで触ってみた


#WebSocket？
以下のスライドでどういうものかは学びました。
http://www.slideshare.net/You_Kinjoh/websocket-10621887


#Goで実装を試す

シンプルにechoサーバを実装すると以下のようになります。

```go:main.go
package main

import (
	"code.google.com/p/go.net/websocket"
	"io"
	"net/http"
)

func echoHandler(ws *websocket.Conn) {
	io.Copy(ws, ws)
}

func main() {

	http.Handle("/echo", websocket.Handler(echoHandler))
	http.Handle("/", http.FileServer(http.Dir("./")))
	if err := http.ListenAndServe(":9999", nil); err != nil {
		panic("ListenAndServe: " + err.Error())
	}

}
```

```html:index.html

<html>
<head>
	<title>websocket sample</title>
	<script type="text/javascript">
	// var wsUri = "ws://echo.websocket.org/"; 
	var wsUri = "ws://localhost:9999/echo"; 

	var output;  
	function init() { 
		output = document.getElementById("output"); 
		testWebSocket(); 
	} 
		 
	function testWebSocket() { 
		websocket = new WebSocket(wsUri); 
		websocket.onopen = function(evt) { 
			onOpen(evt) 
		}; 
		websocket.onclose = function(evt) { 
			onClose(evt) 
		}; 
		websocket.onmessage = function(evt) { 
			onMessage(evt) 
		}; 
		websocket.onerror = function(evt) { 
			onError(evt) 
		}; 
	}  

	function onOpen(evt) { 
		writeToScreen("CONNECTED"); 
		doSend("websocketにメッセージを送信"); 
	}  

	function onClose(evt) { 

		writeToScreen("DISCONNECTED"); 
	}  

	function onMessage(evt) { 
		writeToScreen('<span style="color: blue;">RESPONSE: ' + jsonData.Msg+'</span>'); 
		websocket.close(); 
	}  

	function onError(evt) { 
		writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data); 
	}  

	function doSend(message) { 
		websocket.send(message); 
	}  

	function writeToScreen(message) { 
		var pre = document.createElement("p"); 
		pre.style.wordWrap = "break-word"; 
		pre.innerHTML = message; 
		output.appendChild(pre); 
	}  

	window.addEventListener("load", init, false);
	</script>
</head>
<body>
	<h2>WebSocket Test</h2>  
	<div id="output"></div>
</body>
</html>
```

デフォルトではクロスドメイン通信は許可されていないため、index.htmlをローカルにおいて試すと以下の様なエラーが出ます

``WebSocket connection to 'ws://localhost:9999/echo' failed: Unexpected response code: 403
``

以下のように変更すればクロスドメイン通信できるようになります。

```go:変更箇所
http.Handle("/echo", websocket.Handler(echoHandler))
```

↓

```go:変更内容
http.HandleFunc("/echo",
        func(w http.ResponseWriter, req *http.Request) {
            s := websocket.Server{Handler: websocket.Handler(echoHandler)}
            s.ServeHTTP(w, req)
        })
```



#JSONで通信したい場合

```golang:main.go

package main

import (
	"code.google.com/p/go.net/websocket"
	"log"
	"net/http"
)

func echoHandler(ws *websocket.Conn) {

	type T struct {
		Msg   string
		Count float64
	}

	// receive JSON type T
	var data T
	websocket.JSON.Receive(ws, &data)

	log.Printf("data=%#v\n", data)

	// send JSON type T
	websocket.JSON.Send(ws, data)
}

func main() {

	http.Handle("/", http.FileServer(http.Dir("./")))
	http.HandleFunc("/echo",
		func(w http.ResponseWriter, req *http.Request) {
			s := websocket.Server{Handler: websocket.Handler(echoHandler)}
			s.ServeHTTP(w, req)
		})

	if err := http.ListenAndServe(":9999", nil); err != nil {
		panic("ListenAndServe: " + err.Error())
	}

}

```

```html:index.html

<html>
<head>
	<title>websocket sample</title>
	<script type="text/javascript">
	// var wsUri = "ws://echo.websocket.org/"; 
	var wsUri = "ws://localhost:9999/echo"; 

	var output;  
	function init() { 
		output = document.getElementById("output"); 
		testWebSocket(); 
	} 
		 
	function testWebSocket() { 
		websocket = new WebSocket(wsUri); 
		websocket.onopen = function(evt) { 
			onOpen(evt) 
		}; 
		websocket.onclose = function(evt) { 
			onClose(evt) 
		}; 
		websocket.onmessage = function(evt) { 
			onMessage(evt) 
		}; 
		websocket.onerror = function(evt) { 
			onError(evt) 
		}; 
	}  

	function onOpen(evt) { 
		writeToScreen("CONNECTED"); 
		doSend("websocketにメッセージを送信",Math.random()); 
	}  

	function onClose(evt) { 

		writeToScreen("DISCONNECTED"); 
	}  

	function onMessage(evt) { 

		var jsonData=JSON.parse(evt.data)

		writeToScreen('<span style="color: blue;">RESPONSE: ' + jsonData.Msg+",no:"+jsonData.Count+'</span>'); 
		websocket.close(); 
	}  


	function onError(evt) { 
		writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data); 
	}  

	function doSend(message,number) { 

		writeToScreen("SENT: " + message+",no: "+number);  
		var jsonData={
			Msg:message,
			Count:number
		}

		websocket.send(JSON.stringify(jsonData)); 
	}  

	function writeToScreen(message) { 
		var pre = document.createElement("p"); 
		pre.style.wordWrap = "break-word"; 
		pre.innerHTML = message; 
		output.appendChild(pre); 
	}  

	window.addEventListener("load", init, false);
	</script>
</head>
<body>

	<h2>WebSocket Test</h2>  
	<div id="output"></div>

</body>
</html>
```


#参考

https://github.com/golang-samples/websocket
http://stackoverflow.com/questions/19708330/serving-a-websocket-in-go