Golang WebSocket

myzjeezk  于 2023-09-28  发布在  Go
关注(0)|答案(1)|浏览(67)

有人能帮忙解释一下下面的代码片段是什么意思吗?

var partner = make(chan io.ReadWriteCloser)

func match(c io.ReadWriteCloser) {
    fmt.Fprintln(c, "Waiting for a partner...")
    select {
    case partner <- c:
        // handled by the other goroutine
    case p := <-partner:
        chat(p, c)
    }
}

完整版本:

package main

import (
    "fmt"
    "golang.org/x/net/websocket"
    "html/template"
    "io"
    "log"
    "net/http"
)

const listenAddr = "localhost:4000"

type socket struct {
    conn *websocket.Conn
    done chan bool
}

func (s socket) Read(b []byte) (int, error) {
    return s.conn.Read(b)
}

func (s socket) Write(b []byte) (int, error) {
    return s.conn.Write(b)
}

func (s socket) Close() error {
    s.done <- true
    return nil
}

var rootTemplate = template.Must(template.New("root").Parse(`
<!DOCTYPE html>
<html>
    <head>
        <title>Websocket Chat - Golang</title>
        <meta charset="UTF-8"/>
        <script>
            var input, output, websocket;

            function showMessage(msg) {
                var p = document.createElement("p");
                p.innerHTML = msg;
                output.appendChild(p);
            }
        
            function onMessage(e) {
                showMessage(e.data);
            }
            
            function onClose() {
                showMessage("Connection closed.");
            }
            
            function onKeyUp(e) {
                if (e.keyCode === 13) {
                    sendMessage();
                }
            }
            
            function sendMessage() {
                var msg = input.value;
                input.value = "";
                websocket.send(msg + "\n");
                showMessage(msg);
            }
            
            function init() {
                input = document.getElementById("input");
                input.addEventListener("keyup", onKeyUp, false);
                output = document.getElementById("output");
                websocket = new WebSocket("ws://{{.}}/socket");
                websocket.onmessage = onMessage;
                websocket.onclose = onClose;
            }
            
            window.addEventListener("load", init);
        </script>
    </head>
    <body>
        Say: <input id="input" type="text"/>
        <div id="output"></div>
    </body>
</html>
`))

func rootHandler(w http.ResponseWriter, r *http.Request) {
    rootTemplate.Execute(w, listenAddr)
}

func socketHandler(conn *websocket.Conn) {
    s := socket{conn: conn, done: make(chan bool)}
    go match(s)
    <-s.done
}

var partner = make(chan io.ReadWriteCloser)

func match(c io.ReadWriteCloser) {
    fmt.Fprintln(c, "Waiting for a partner...")
    select {
    case partner <- c:
        // handled by the other goroutine
    case p := <-partner:
        chat(p, c)
    }
}

func chat(a, b io.ReadWriteCloser) {
    fmt.Fprintln(a, "Found one! Say hi.")
    fmt.Fprintln(b, "Found one! Say hi.")
    errc := make(chan error, 1)
    go cp(a, b, errc)
    go cp(b, a, errc)
    if err := <-errc; err != nil {
        log.Println(err)
    }
    a.Close()
    b.Close()
    go io.Copy(b, a)
    io.Copy(a, b)
}

func cp(w io.Writer, r io.Reader, errc chan<- error) {
    _, err := io.Copy(w, r)
    errc <- err
}

func main() {
    http.HandleFunc("/", rootHandler)
    http.Handle("/socket", websocket.Handler(socketHandler))
    err := http.ListenAndServe(listenAddr, nil)
    if err != nil {
        log.Fatal(err)
    }
}

不太明白为什么这个聊天功能可以执行时,第二个加入者加入聊天频道。

ars1skjm

ars1skjm1#

看起来HTTP处理程序创建了一个Web Socket,并开始等待另一方连接。这是因为当处理HTTP请求时,处理程序调用match,它将在select上阻塞,因为partner通道既不可读也不可写。没有goroutine监听它,或者发送给它。
当第二个请求到来时,match再次被另一个goroutine调用。现在有两个goroutine,它们可以 * 匹配 *。其中一个goroutine可以发送到partner通道,另一个接收它。传输的对象是读写器,然后用于两个伙伴之间的通信。

相关问题