【问题标题】:socket.io client using Go使用 Go 的 socket.io 客户端
【发布时间】:2017-10-04 09:43:56
【问题描述】:

从一个有效的socket.io 示例开始(后端:Python/Flask,前端:socket.io.js v2.0.3),我现在尝试使用 Go 设置客户端,但甚至无法通过握手阶段。为长篇道歉......(最后我还添加了一个 Python 客户端,它可以在 Go 中实现我想要实现的功能)

(以下作品):


后端:

@socketio.on('connect', namespace='/endpoint')
def connect():
    print("Client connected with request sid "+request.sid)

@socketio.on('join', namespace='/endpoint')
def join(message):
    print("Server received from client:" +message)
    print("Client just joined room with request sid "+request.sid)
    join_room(request.sid)

前端:

namespace = '/endpoint';
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace);

var client_join_message = "This is a client";    
socket.emit('join', client_join_message);

开发者工具:我注意到一些请求,直到浏览器和服务器选择使用 websockets 和交换框架:

http://localhost:5000/socket.io/?EIO=3&transport=polling&t=LxcgetJ
http://localhost:5000/socket.io/?EIO=3&transport=polling&t=Lxcgetf&sid=025e105a5093467d994a891367380aa3
http://localhost:5000/socket.io/?EIO=3&transport=polling&t=Lxcgeti&sid=025e105a5093467d994a891367380aa3
ws://localhost:5000/socket.io/?EIO=3&transport=websocket&sid=025e105a5093467d994a891367380aa3
http://localhost:5000/socket.io/?EIO=3&transport=polling&t=Lxcgetw&sid=025e105a5093467d994a891367380aa3
http://localhost:5000/socket.io/?EIO=3&transport=polling&t=Lxcgetx&sid=025e105a5093467d994a891367380aa3

服务器日志:

"GET /socket.io/?EIO=3&transport=polling&t=LxcgetJ HTTP/1.1" 200 381 0.000322
Client connected with request sid 025e105a5093467d994a891367380aa3
"POST /socket.io/?EIO=3&transport=polling&t=Lxcgetf&sid=025e105a5093467d994a891367380aa3 HTTP/1.1" 200 219 0.000806
(6450) accepted ('127.0.0.1', 45034)
"GET /socket.io/?EIO=3&transport=polling&t=Lxcgeti&sid=025e105a5093467d994a891367380aa3 HTTP/1.1" 200 227 0.003941
"POST /socket.io/?EIO=3&transport=polling&t=Lxcgetw&sid=025e105a5093467d994a891367380aa3 HTTP/1.1" 200 219 0.001650
"GET /socket.io/?EIO=3&transport=polling&t=Lxcgetx&sid=025e105a5093467d994a891367380aa3 HTTP/1.1" 200 215 0.000235
Server received from client:This is a client
Client just joined room with request sid 025e105a5093467d994a891367380aa3


我对 Go 的尝试,(不起作用):


代码来自github.com/graarh/golang-socketio中的这个client示例:

package main

import (
    "github.com/graarh/golang-socketio"
    "github.com/graarh/golang-socketio/transport"
    "log"
    "runtime"
    "time"
)

func main() {

    runtime.GOMAXPROCS(runtime.NumCPU())

    c, err := gosocketio.Dial(
        gosocketio.GetUrl("127.0.0.1", 5000, false),
        transport.GetDefaultWebsocketTransport())
    if err != nil {
        log.Fatal(err)
    }

    err = c.On(gosocketio.OnDisconnection, func(h *gosocketio.Channel) {
        log.Fatal("Disconnected")
    })
    if err != nil {
        log.Fatal(err)
    }

    err = c.On(gosocketio.OnConnection, func(h *gosocketio.Channel) {
        log.Println("Connected")
    })
    if err != nil {
        log.Fatal(err)
    }

    time.Sleep(1 * time.Second)
}

Go 代码输出:

Connected

服务器日志:

"GET /socket.io/?EIO=3&transport=websocket HTTP/1.1" 200 0 1.004291

我有什么遗漏的吗?使用 Go 代码,我看不到任何 sidtransport=polling ......此外,只有几个问题标记为 [go] [socket.io],这让我觉得我选择了错误的路径......我会感谢您对此的任何想法和想法。


@约翰·韦尔登

您的代码生成以下内容:

客户:

$ go run gotest5.go 
2017/10/11 11:21:40 Connected
2017/10/11 11:21:40 result ""
2017/10/11 11:21:40 Done

服务器:

(4380) wsgi starting up on http://127.0.0.1:5000
(4380) accepted ('127.0.0.1', 38860)
127.0.0.1 - - [11/Oct/2017 11:21:40] "GET /socket.io/?EIO=3&transport=websocket HTTP/1.1" 200 0 0.003100

请注意,服务器函数 on.('connect'...)on.('join',...) 没有生成日志。


Python 客户端(有效):

from socketIO_client import SocketIO, BaseNamespace

class ThisNamespace(BaseNamespace):
    def on_connect(self):
        print('[Connected]')
    def on_reconnect(self):
        print('[Reconnected]')
    def on_disconnect(self):
        print('[Disconnected]')

with SocketIO('127.0.0.1', 5000, ThisNamespace) as socketIO:
    this_namespace = socketIO.define(ThisNamespace, '/endpoint')

客户端日志:

python3 test.py 
[Connected]
[Disconnected]
[Disconnected]

服务器日志:

(6047) wsgi starting up on http://127.0.0.1:5000
(6047) accepted ('127.0.0.1', 38900)
127.0.0.1 - - [11/Oct/2017 11:53:27] "GET /socket.io/?t=1507712007314-0&transport=polling&EIO=3 HTTP/1.1" 200 381 0.000859
(6047) accepted ('127.0.0.1', 38902)
Client connected with request sid 919ed69264dd4e9f93e7af0294970dbd
Client disconnected with request.sid 919ed69264dd4e9f93e7af0294970dbd
127.0.0.1 - - [11/Oct/2017 11:53:27] "GET /socket.io/?sid=919ed69264dd4e9f93e7af0294970dbd&transport=websocket&EIO=3 HTTP/1.1" 200 0 0.032171

【问题讨论】:

  • Dial 函数用于作为客户端连接到服务器,但您正在尝试创建服务器。您需要使用库文档中显示的NewServer
  • 谢谢加文。我想连接到服务器,而不是创建一个新的。所以Dial() 的使用在这里是正确的,不是吗?
  • 抱歉,我误读并认为您试图将后端移动到 Go。我注意到您当前的设置,通过 http 的请求被记录并具有transport=polling,通过 ws 的请求被记录为客户端连接和transport=websocket。但是,当您使用 Go 客户端时,您会使用 transport=websocket 记录一个 http 请求。
  • 是的,你是对的。通过深入挖掘golang-socketio 的源代码,我看不到任何选项可以在浏览器中执行与 javascript 相同的操作。这个握手/轮询阶段也没有很好的记录:Document the handshake process #10
  • 事实上,你的 JS 和 Go 客户端的工作方式不同。 JS 使用轮询,Go 尝试使用 websockets。您能否仅将可用传输限制为 websocket?像这样:io.connect("http://your.domain.com", {transports: ['websocket']});

标签: go websocket socket.io


【解决方案1】:

我认为你做得对,只是你忘了实际发送 join 消息,可能是这样的:

package main

import (
        "log"
        "runtime"
        "sync"
        "time"

        "github.com/graarh/golang-socketio"
        "github.com/graarh/golang-socketio/transport"
)

func doSomethingWith(c *gosocketio.Client, wg *sync.WaitGroup) {
        if res, err := c.Ack("join", "This is a client", time.Second*3); err != nil {
                log.Printf("error: %v", err)
        } else {
                log.Printf("result %q", res)
        }
        wg.Done()
}

func main() {

        runtime.GOMAXPROCS(runtime.NumCPU())

        c, err := gosocketio.Dial(
                gosocketio.GetUrl("127.0.0.1", 3003, false),
                transport.GetDefaultWebsocketTransport())
        if err != nil {
                log.Fatal(err)
        }

        err = c.On(gosocketio.OnDisconnection, func(h *gosocketio.Channel) {
                log.Fatal("Disconnected")
        })
        if err != nil {
                log.Fatal(err)
        }

        err = c.On(gosocketio.OnConnection, func(h *gosocketio.Channel) {
                log.Println("Connected")
        })
        if err != nil {
                log.Fatal(err)
        }

        wg := &sync.WaitGroup{}
        wg.Add(1)
        go doSomethingWith(c, wg)
        wg.Wait()
        log.Printf("Done")
}

注意 goroutine 调用实际上将“加入”消息传递给服务器的函数。

另外,请注意使用 sync.WaitGroup 阻塞直到 goroutine 完成,而不是使用 time.Sleep() 等待。

【讨论】:

  • 谢谢约翰。这也是我一直在使用的示例。出于某种原因,两个服务器函数 socketio.on('connect'...)socketio.on('join'...) 永远不会执行。我真的认为这个库试图直接连接到ws,并且没有实现socket.io 作为协议所需的初始步骤。
  • 嗯,两个主要区别是 1) 您只等待 1 秒而不是 60 秒,以及 2) 您实际上并没有进行任何 Join 调用 - 该示例发出几个 @ 987654330@ goroutines 中的请求,然后等待 60 秒等待 goroutines 完成。
  • @tgogos - 我已经用一个示例更新了我的答案,该示例应该可以为您提供所需的结果。
  • 非常感谢约翰的努力。我已将您的代码结果包含在我的问题中。
  • 我还添加了python客户端的结果
【解决方案2】:

根据上面的评论,我们发现 websocket 连接本身正在工作。我认为问题就在这里 - socket.io 是多年前开发的,当时大多数浏览器和中间服务器/代理/路由器都不能很好地支持原生 WebSocket。因此,它在升级和降级连接(例如长轮询)时有特殊的检查和回退。如果您已经安装了连接,则无需与其他协议进行特殊密钥交换即可开始工作。

尝试开始使用连接并在应用程序级逻辑执行后续步骤(Join 等)。有效吗?

我认为现在 99% 的客户都很好地支持了 WS。如果您不想失去某些客户无法工作的机会,您可以将sockets.io 保留在项目中。但有时你必须在 WS 中实现它的连接逻辑。

【讨论】:

  • 感谢 Eugene 的努力,我在搜索此内容时或多或少得出了相同的结论...
猜你喜欢
  • 1970-01-01
  • 2016-03-09
  • 2011-08-12
  • 1970-01-01
  • 2019-11-04
  • 2015-08-21
  • 1970-01-01
  • 2011-11-13
  • 1970-01-01
相关资源
最近更新 更多