英文:
Golang websocket handler
问题
我在使用Node.js写了很长时间之后,开始学习Golang,并且对如何实现处理程序有些好奇。我选择使用Gorilla Websocket,因为我了解到它是最可靠的包。
例如,在socket.io中,你可以使用简单的socket.on函数,根据传入的JSON中的"name"参数调用一个函数。
Gorilla websocket没有实现这样的功能,所以我的问题是,我是否需要实现类似socket.io的逻辑来实现我想要的功能?
也就是说,根据在websocket中传输的值执行某个过程?
如果是这样的话,我需要分别在客户端(我在前端使用AngularJS)和服务器端自己实现它——在AngularJS中根据JSON中的值进行switch case语句,然后在Go中进行相同的操作。而且,这是最高效的方式吗?
谢谢!
英文:
I've started learning Golang after writing in Node.js for a long time and I'm a bit curious as to how am I to implement a handler - I've opted to use Gorilla Websocket since I understood it's the most reliable package out there.
In socket.io for example you have the simple socket.on function that allows me to call a function based on the "name" parameter passed in JSON.
Gorilla websocket doesn't implement such a thing, so my question is am I to sort of implement the logic behind socket.io in order to achieve what I want ?
As in do a certain procedure based on the value transferred in the websocket ?
If so - I need to implement it both client (I'm using AngularJS on the front-end) and server side separately by my own - make a switch case statement based on a value I get in JSON both in AngularJS for the front-end and in Go for the back-end, and also - is that the most efficient way ?
Thanks !
答案1
得分: 5
如果你已经使用JavaScript一段时间了,实现自己的socket.on和socket.emit版本非常容易。这是我为自己的项目制作的一个版本,如果你需要的话可以使用:
// 例如:
// let socket = new Socket("ws://w/e");
// socket.on('connected', () => { console.log('Connected'); });
// socket.emit('lobby join', { data: { username: 'Boo' } });
// 使用ES2015和Babel
import { EventEmitter } from 'events';
class Socket {
    constructor(wsurl, ee = new EventEmitter()) {
        let ws = new WebSocket(wsurl);
        this.ee = ee;
        this.ws = ws;
        ws.onmessage = this.message.bind(this);
        ws.onopen = this.open.bind(this);
        ws.onclose = this.close.bind(this);
    }
    on(name, fn) {
        this.ee.on(name, fn);
    }
    off(name, fn) {
        this.ee.removeListener(name, fn);
    }
    emit(name, data) {
        const message = JSON.stringify({ name, data });
        this.ws.send(message);
    }
    message(e) {
        try {
            const msgData = JSON.parse(e.data);
            this.ee.emit(msgData.name, msgData.data);
        } catch (err) {
            let error = {
                message: err
            };
            console.log(err);
            this.ee.emit(error.message);
        }
    }
    open() {
        this.ee.emit('connected');
    }
    close() {
        this.ee.emit('disconnected');
    }
}
export default Socket;
这样你就可以使用常见的socket.on('event', fn);等方法了。
至于服务器端的处理:
对于接收消息,我个人只是创建了一个switch语句,将传入的字符串与函数匹配,例如:
// readPump将websocket连接中的消息传输到hub。
func (c *connection) readPump() {
    defer c.ws.Close()
    for {
        _, message, err := c.ws.ReadMessage()
        if err != nil {
            break
        }
        var incMessage interface{}
        err = json.Unmarshal(message, &incMessage)
        if err != nil {
            log.Println(err)
        }
        incMessageMap := incMessage.(map[string]interface{})
        switch incMessageMap["name"] {
        case "lobby join":
            // 处理加入操作
        case "lobby leave":
            // 处理离开操作
        }
    }
}
对于发送消息,我在连接上有一个send channel,它存储在一个映射中,当我需要发送时,我有一个简单的结构体,它接受消息名称和数据,例如:
type wsMsg struct {
    Name string                 `json:"name"`
    Data map[string]interface{} `json:"data"`
}
c.send <- wsMsg{
    "user joined",
    map[string]interface{}{
        "username": "Booh",
    },
}
然后在客户端,它会以如下形式出现:
socket.on('user joined', (msg) => {
    console.log(msg); // { username: "Booh" }
});
我建议查看gorilla的示例:https://github.com/gorilla/websocket/tree/master/examples/chat
英文:
If you've been using Javascript for a while it is really easy to implement your own version of socket.on and socket.emit here is one I made for my own projects but you can have it if you need,
// e.g.
// let socket = new Socket("ws://w/e");
// socket.on('connected', () => { console.log('Connected'); });
// socket.emit('lobby join', { data: { username: 'Boo' } });
// Using ES2015 with Babel
import {EventEmitter} from 'events';
class Socket {
    constructor(wsurl, ee = new EventEmitter()) {
        let ws = new WebSocket(wsurl);
        this.ee = ee;
        this.ws = ws;
        ws.onmessage = this.message.bind(this);
        ws.onopen = this.open.bind(this);
        ws.onclose = this.close.bind(this);
    }
    on(name, fn) {
        this.ee.on(name, fn);
    }
    off(name, fn) {
        this.ee.removeListener(name, fn);
    }
    emit(name, data) {
        const message = JSON.stringify({name, data});
        this.ws.send(message);
    }
    message(e) {
        try {
            const msgData = JSON.parse(e.data);
            this.ee.emit(msgData.name, msgData.data);
        }
        catch(err) {
            let error = {
                message: err
            }
            console.log(err)
            this.ee.emit(error.message)
        }
    }
    open() {
        this.ee.emit('connected');
    }
    close() {
        this.ee.emit('disconnected');
    }   
}
export default Socket
This will let you use your common socket.on('event', fn); and what not
As for handling it on the servers end:
For receiving messages, I personally just make a switch statement that will match an incoming string to a function, e.g.:
// readPump pumps messages from the websocket connection to the hub.
func (c *connection) readPump() {
	defer c.ws.Close()
	for {
		_, message, err := c.ws.ReadMessage()
		if err != nil {
			break
		}
		var incMessage interface{}
		err = json.Unmarshal(message, &incMessage)
		if err != nil {
			log.Println(err)
		}
		incMessageMap := incMessage.(map[string]interface{})
		switch incMessageMap["name"] {
		case "lobby join":
             // Do something to handle joining
	    case "lobby leave":
             // Do something to handle leaving
		}
	}
}
For sending them I have a send channel on my connections that is stored in a map and when I need to emit I have a simple struct that takes a message name, and data, e.g.:
type wsMsg struct {
    Name string                 `json:"name"`
    Data map[string]interface{} `json:"data"`
}
c.send <- wsMsg{
     "user joined",
     map[string]interface{}{
          "username": "Booh",
     },
}
Then on the client side it would come as
socket.on('user joined', (msg) => {
    console.log(msg) // { username: "Booh" }
});
I suggest looking at the examples on gorillas git: https://github.com/gorilla/websocket/tree/master/examples/chat
答案2
得分: 1
这是一个使用Golang的WebSocket来流式传输视频的工作示例。你可以在以下链接找到它:https://github.com/interviewparrot/OpenAVStream
如果你对这个示例满意,请告诉我。
英文:
Here is an working example of golang websocket to stream video
https://github.com/interviewparrot/OpenAVStream
Let me know if it is good enough
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论