socket.io client using Go

2019-04-07 14:55发布

Starting with a working socket.io example (back-end: Python/Flask, front-end: socket.io.js v2.0.3), I now try to set up a client with Go but can't even pass the handshake phase. Apologies for the long post... (At the end I have also added a Python client which does what I want to implement in Go)

(The following work):


back-end:

@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)

front-end:

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);

Developer tools: I notice a few requests until the browser and the server select to use websockets and exchange frames:

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

Server logs:

"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


My try with Go, (doesn't work):


The code comes from this client example in github.com/graarh/golang-socketio:

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 code output:

Connected

Server logs:

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

Is there anything that I'm missing? With the Go code I don't see any sid, transport=polling... Also, there are only a few questions tagged with [go] [socket.io], which makes me think I've chosen the wrong path... I would be grateful for any thoughts, ideas on this.


@John Weldon

Your code produces the following:

Client:

$ 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

Server:

(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

Notice that the server functions on.('connect'...) and on.('join',...) didn't produce logs.


Python client (it works):

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')

client logs:

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

server logs:

(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

2条回答
啃猪蹄的小仙女
2楼-- · 2019-04-07 15:15

According to commentws above, we've found websocket connection itself is working. I think problem is here - socket.io was developed many years ago when native WebSockets were not well supported by majority of browsers and inermediate servers/proxies/routers. So it has a special checks and fallbacks when to upgrade and downgrade a connection (to longpolling for example). If you have already installed connection you may start working without special key exchanges with another protocol.

Try to start using connection and performing next steps at application level logics (Join and so on). Is it working?

I think nowadays WS are supported well for 99% of clients. If you want not to loose chance some client will be not working you may keep sockets.io in project. But sometimes you'll have to realize its connections logics in WS.

查看更多
家丑人穷心不美
3楼-- · 2019-04-07 15:35

I think you're doing it right except you forgot to actually send the join message, maybe something like:

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")
}

Notice the goroutine call to the function that actually communicates the 'join' message to the server.

Also, notice the use of a sync.WaitGroup to block until the goroutine completes, instead of using time.Sleep() to wait.

查看更多
登录 后发表回答