12767


GolangでWebsocketをつかって写真を共有するWeb Applicationを作っています。

あるクライアントが写真を投稿すると、すぐに、ほかのクライアントに表示されている写真がそれに更新されるようにしたいです。  
そのために`*websocket.Conn`を`ws_array`という配列に入れ、データをSendするときはforで配列から取り出してデータを送信しています。

ある写真が投稿されたら、ほかのクライアントに表示されている写真も投稿と同時に更新されるようにしたいのですが、写真が投稿されてもほかのクライアントの写真が更新されません。  
なぜなのでしょうか?

Serverのコード

[code]

    
    package main
    
    import (
        "database/sql"
        "fmt"
        "github.com/go-gorp/gorp"
        _ "github.com/mattn/go-sqlite3"
        "golang.org/x/net/websocket"
        "log"
        "net/http"
    )
    
    type Picture struct {
        Id   int64
        Data []byte
        Name string
        Type string
    }
    
    var debug = false
    
    var photodb = "./db/photo.sqlite3"
    
    func main() {
        http.Handle("/layouts/css/", http.StripPrefix("/layouts/css/", http.FileServer(http.Dir("layouts/css"))))
        http.Handle("/", http.FileServer(http.Dir(".")))
        http.Handle("/chat", websocket.Handler(data_handle))
        fmt.Println(":8249")
        err := http.ListenAndServe(":8249", nil)
        if err != nil {
            panic("ListenAndServe: " + err.Error())
        }
    }
    
    func InitDb() (*gorp.DbMap, error) {
        db, err := sql.Open("sqlite3", photodb)
        if err != nil {
            fmt.Println(err)
            return nil, err
        }
        dbmap := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
        dbmap.AddTableWithName(Picture{}, "picture").SetKeys(true, "Id")
        err = dbmap.CreateTablesIfNotExists()
        if err != nil {
            return nil, err
        }
        return dbmap, nil
    }
    
    func insertPic(pic *Picture) {
        dbmap, err := InitDb()
        if err != nil {
            log.Fatalln("InitDb error:", err)
        }
        err = dbmap.Insert(pic)
        if err != nil {
            log.Fatalln("Insert error:", err)
        }
    }
    
    func data_receive(ws *websocket.Conn) {
        for {
            var b Picture
            if err := websocket.JSON.Receive(ws, &b); err != nil {
                if debug {
                    fmt.Println(b)
                }
                fmt.Println("Receive error:", err)
            } else {
                insertPic(&b)
                for _, con := range ws_array {
                    go func() {
                        err = websocket.JSON.Send(con, b)
                        fmt.Println("con:", con)
                        if err != nil {
                            fmt.Println("Send error:", err)
                        }
                    }()
                }
            }
        }
    }
    
    var ws_array []*websocket.Conn // *websocket.Connを入れる配列
    
    func data_handle(ws *websocket.Conn) {
        ws_array = append(ws_array, ws)
        data_receive(ws)
    }
    
    
    
[/code]

ClientのJavaScript

[code]

    
    var ws = new WebSocket("ws://localhost:8249/chat")
    ws.onerror = function (err) {
        console.error("Error: " + err);
    }
    var img = document.getElementById("hello");
    var f = document.getElementById("file");
    var file_reader = new FileReader();
    f.onchange = function () {
        var filelist = this.files;
        var file = filelist[0];
        file_reader.onload = function (e) {
            var data = e.target.result;
            var b64 = data.slice(data.indexOf(",") + 1);
            var s = {"Name": file.name, "Data": b64, "Type": file.type};
            console.log(JSON.stringify(s));
            ws.send(JSON.stringify(s));
    
        }
        file_reader.readAsDataURL(file);
    
    }
    
    ws.onmessage = function (e) {
        console.log("Received");
        var obj = JSON.parse(e.data);
        var bytes = atob(obj.Data.replace(/^.*,/, ''));
        var b = new Uint8Array(obj.Data.length);
        for (var i = 0; i < obj.Data.length; i++) {
            b[i] = bytes.charCodeAt(i);
        }
        var blob = new Blob([b.buffer], {type: obj.Type});
        var url = URL.createObjectURL(blob);
        img.src = url;
    
    }
    
    
    
[/code]

HTML

[code]

    
    <!DOCTYPE html>
    <html lang="ja">
        <head>
            <title>Websocket json</title>
            <meta charset="utf-8">
            <link rel="stylesheet" href="websocket.css">
        </head>
        <body>
            <input type="file" id="file" accept="image/*">
            <img id="hello">
            <script src="websocket_json.js"></script>
        </body>
    </html>
    
    
    <!DOCTYPE html>
    <html lang="ja">
        <head>
            <title>Websocket json</title>
            <meta charset="utf-8">
            <link rel="stylesheet" href="websocket.css">
        </head>
        <body>
            <input type="file" id="file" accept="image/*">
            <img id="hello">
            <script src="websocket_json.js"></script>
        </body>
    </html>
    
    
    
[/code]


CC BY-SA 3.0
2015-07-18T13:03:56.523
12471
2015-07-28T07:54:18.977
2015-07-20T13:00:03.937
5246
5246
question
javascript go websocket
GolangのWebsocketでクライアントが送信したデータが他のクライアントに反映されない


ブロードキャスト時のループ

[code]

            for _, con := range ws_array {
                go func() {
                    err = websocket.JSON.Send(con, b)
                    fmt.Println("con:", con)
                    if err != nil {
                        fmt.Println("Send error:", err)
                    }
                }()
            }
    
[/code]

これを

[code]

            for _, con := range ws_array {
                con := con
                go func() {
                    err = websocket.JSON.Send(con, b)
                    fmt.Println("con:", con)
                    if err != nil {
                        fmt.Println("Send error:", err)
                    }
                }()
            }
    
[/code]

にすれば直ると思います。for ループ内で goroutine を使っているので最終のコネクションだけに応答が飛んでしまっているのだと思います。


CC BY-SA 3.0
2015-07-28T07:54:18.977
12767
2015-07-28T07:54:18.977
440
12471
answer