m_shige1979のときどきITブログ

プログラムの勉強をしながら学習したことや経験したことをぼそぼそと書いていきます

Github(変なおっさんの顔でるので気をつけてね)

https://github.com/mshige1979

go言語の学習:websocketで画像を送信し、webで表示

できたの


なにこれ?

websocketサーバより1秒単位で画像をバイナリ形式で送信したもの

ソース(サーバ側)

package main

import (
	"log"
	"net/http"
	"golang.org/x/net/websocket"
	"time"
	"io/ioutil"
	"image"
	"gocv.io/x/gocv"
	"image/color"
	"bytes"
	"image/jpeg"
	"os/user"
)

var (
	black = color.RGBA{0, 0, 0, 0}
)

func main() {
	name := "server"
	log.Println(name + " start")

	http.Handle("/ws", websocket.Handler(WsHandler))
	err := http.ListenAndServe(":8001", nil)
	if err != nil {
		panic("ListenAndServe: " + err.Error())
	}

	log.Println(name + " end")
}

func WsHandler(ws *websocket.Conn) {
	log.Println("connect")

	// 自動送信
	go autoSend(ws)

	// 受信処理監視
	for {
		var b []byte
		err := websocket.Message.Receive(ws, &b)
		if err != nil {
			log.Println(err)
			break
		}
	}
}

// 任意の画像を送信する
func autoSend(ws *websocket.Conn) {
	t := time.NewTicker(1 * time.Second)
	for {
		select {
			case <-t.C:
				// ユーザディレクトリ取得
				user, err := user.Current()
				if err != nil {
					log.Println(err)
					return
				}

				// 画像ファイル読み込み
				b, err := ioutil.ReadFile(user.HomeDir + "/Desktop/" + "pug3_pic1.jpg")
				if err != nil {
					break
				}

				// 画像変換
				atom, err := gocv.IMDecode(b, gocv.IMReadUnchanged)
				if err != nil {
					log.Println(err)
					return
				}
				defer atom.Close()

				// 日時取得
				now := time.Now()

				// 偶数
				if int(now.Second()) % 2 == 0 {
					gocv.Rectangle(&atom, image.Rect(400, 400, 900, 700), black, 2)
				} else {
					gocv.Rectangle(&atom, image.Rect(400, 400, 900, 700), black, -1)
				}

				// 文字列を出力
				timeStr := now.Format("2006/01/02 15:04:05")
				gocv.PutText(&atom, timeStr, image.Pt(20, atom.Rows() - 40), gocv.FontHersheyComplex, 1, black, 1)

				// 画像に変換
				image, err := atom.ToImage()
				if err != nil {
					log.Println(err)
					return
				}
				var jpegBytes []byte
				buf := bytes.NewBuffer(jpegBytes)
				if err := jpeg.Encode(buf, image, nil); err != nil {
					log.Println(err)
				}
				b = buf.Bytes()

				websocket.Message.Send(ws, b)
				log.Println("send")
		}
	}
}

ソース(クライアント側)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <img id="img1" src="">

<script>
    var uri = "ws://localhost:8001" + "/ws";
    webSocket = new WebSocket(uri);
    webSocket.binaryType = 'blob';
    webSocket.onopen = function(e) {
        console.log("open");
    };
    webSocket.onmessage = function(e) {
        console.log("message");
        var data = e.data;
        if (data.constructor === Blob) {
            document.getElementById('img1').src = URL.createObjectURL(data);
        }
    };
    webSocket.onclose = function(e) {
        console.log("close");
    };
</script>
</body>
</html>

ソース(クライアント版2)

package main

import (
	"log"
	"golang.org/x/net/websocket"
	"strconv"
)

var (
	doneCh chan bool
	origin = "http://localhost:8001/"
	url    = "ws://localhost:8001/ws"
)

func main() {
	name := "client"
	log.Println(name + " start")

	doneCh = make(chan bool)

	ws, err := websocket.Dial(url, "", origin)
	if err != nil {
		log.Fatal(err)
		return
	}

	go receiveMsg(ws)

	<-doneCh
	log.Println(name + " end")
}

// 受信
func receiveMsg(ws *websocket.Conn) {
	var b []byte

	for {
		err := websocket.Message.Receive(ws, &b)
		if err != nil {
			log.Println(err)
			doneCh <- true
			break
		}
		log.Printf("Receive datasize=" + strconv.Itoa(len(b)))
	}
}

所感

いろいろ悩んだけど基本は画像をバイナリで送信するだけだった感じ
動画のストリーミングという感じではないのでそこまで難しくないかも…
最初はwebsocketの送受信がうまく行かなかったけどw