Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ConnectionRefusedError not working #487

Closed
databasedav opened this issue May 20, 2020 · 12 comments
Closed

ConnectionRefusedError not working #487

databasedav opened this issue May 20, 2020 · 12 comments
Assignees
Labels

Comments

@databasedav
Copy link
Contributor

databasedav commented May 20, 2020

This is on Python 3.8.2 with

python-engineio==3.12.1
python-socketio==4.5.1
uvicorn==0.11.5

and you can reproduce with

# server.py
import socketio
from socketio.exceptions import ConnectionRefusedError

sock = socketio.ASGIApp(
    socketio.AsyncServer(async_mode="asgi"),
)

@sock.engineio_server.event
async def connect(sid, environ):
    # raise Exception()
    raise ConnectionRefusedError()
# client.py
import asyncio
import socketio

async def test():
    c = socketio.AsyncClient()
    await c.connect('ws://localhost:8002')
    await asyncio.sleep(1)
    await c.disconnect()
    await asyncio.sleep(1)

asyncio.run(test())

and running uvicorn --host 0.0.0.0 --port 8002 server:sock and python client.py

raising an Exception produces the expected behavior.

@miguelgrinberg
Copy link
Owner

Sorry, but I can't reproduce. I get the expected ConnectionError in the client using exact copies of your server and client:

socketio.exceptions.ConnectionError: Connection refused by the server

@databasedav
Copy link
Contributor Author

Hmm not sure why reproduction isn't working. On my end, downgrading to 4.3.1 solves the issue so it seems to be something introduced in 4.4.0. I'm on Ubuntu 20.04 but not sure if that is relevant. I'll investigate further.

@miguelgrinberg
Copy link
Owner

Sorry, I gave your code another run today and I do see the problem. I must have put your server on the standard 8000 port yesterday, instead of the custom 8002 that you are using.

@ysde
Copy link

ysde commented Jul 22, 2020

Hi @miguelgrinberg

I raise ConnectionRefusedError('authentication failed') in on_connect event.

But the client only got ConnectionError('Connection error') when I print the exception.

The goal is to get the authentication failed message to tell the client. Just like the instruction in the documentation.

Sometimes it is useful to pass data back to the client being rejected. In that case instead of returning False socketio.exceptions.ConnectionRefusedError can be raised, and all of its arguments will be sent to the client with the rejection message:

@sio.event
def connect(sid, environ):
    raise ConnectionRefusedError('authentication failed')

======================================================================
Here is the sample code

try:
    sio.connect('http://xxxxxxxxxxxxx')
except ConnectionError as ex:
    print(repr(ex))

@miguelgrinberg
Copy link
Owner

@ysde can you please run your application with engineio_logger=True set in the server object? That should give me more idea of what's going on. Thanks.

@databasedav
Copy link
Contributor Author

@miguelgrinberg I think this issue might have resurfaced? here's a repro:

Pipfile

[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]
python-socketio = "*"
uvicorn = {extras = ["standard"],version = "*"}
aiohttp = "*"

[requires]
python_version = "3.8"

server.py

import socketio
from socketio.exceptions import ConnectionRefusedError

sock = socketio.ASGIApp(
    socketio.AsyncServer(
        async_mode="asgi",
        monitor_clients=False,
        engineio_logger=True
    ),
)

@sock.engineio_server.event
async def connect(sid, environ):
    # raise Exception('custom')
    raise ConnectionRefusedError('custom')

client.py

# client.py
import asyncio
import socketio
import traceback

async def test():
    c = socketio.AsyncClient()
    try:
        await c.connect('ws://localhost:8002')
        await asyncio.sleep(1)
        await c.disconnect()
        await asyncio.sleep(1)
    except:
        traceback.print_exc()

asyncio.run(test())

here's what i see from the server after running uvicorn --host 0.0.0.0 --port 8002 server:sock and then python client.py

Server initialized for asgi.
INFO:     Started server process [54517]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8002 (Press CTRL+C to quit)
iygUxmw6v1ROJCEVAAAA: Sending packet OPEN data {'sid': 'iygUxmw6v1ROJCEVAAAA', 'upgrades': ['websocket'], 'pingTimeout': 5000, 'pingInterval': 25000}
INFO:     127.0.0.1:56026 - "GET /socket.io/?transport=polling&EIO=4&t=1609627767.9831548 HTTP/1.1" 200 OK
iygUxmw6v1ROJCEVAAAA: Received request to upgrade to websocket
INFO:     ('127.0.0.1', 56026) - "WebSocket /socket.io/" [accepted]
iygUxmw6v1ROJCEVAAAA: Upgrade to websocket successful
iygUxmw6v1ROJCEVAAAA: Received packet MESSAGE data 0
iygUxmw6v1ROJCEVAAAA: Sending packet MESSAGE data 4{"message":"custom"}

the client never raises an exception ...

based on the logs, it looks like the server sends out the connection refused message but doesn't actually refuse the connection?

thanks!

@miguelgrinberg
Copy link
Owner

@databasedav the Socket.IO protocol changed and the way this works had to change to accommodate the new version of the protocol. A connection rejected exception triggers a connect_error event in the client, but it does not raise an exception anymore, since the connection did not actually fail, the server just refused it.

@databasedav
Copy link
Contributor Author

databasedav commented Jan 2, 2021

@miguelgrinberg ok got it, so it's up to the client to disconnect after getting a connect_error?

edit: ideally i want to send the client the reason for the rejection and then close the connection without invoking my disconnect handler (which undoes stuff done after an unrefused connection)

@miguelgrinberg
Copy link
Owner

@databasedav the disconnect handler should not be invoked for a rejected connection. Are you saying that it is being invoked in your application? The client should be disconnecting on its own after receiving the rejection and invoking the connect_error event handler.

@kouohhashi
Copy link

Hi, is this issue solved?

I use Python for server and Javascript for client and I can not get ConnectionRefusedError exception at client.

server-side (Python):

python-socketio: 5.5.1  
python-engineio: 4.3.1

client-side (Javascript):

socket.io-client: 4.4.1

ConnectionRefusedError do not even emit disconnect, or connect_error event at all.
Is there any way to get errors like below?

try {
  socketio.connect()
} catch (err) {
 console.log("err: ", err) // <-- here we get message from ConnectionRefusedError
}

Thanks in advance.

@miguelgrinberg
Copy link
Owner

@kouohhashi this package has no control over how the JavaScript client reports connection errors. See the connect_error event in their docs: https://socket.io/docs/v4/client-socket-instance/#events

@mgkeeley
Copy link

mgkeeley commented Jun 4, 2024

For others coming here with the same error:
Make sure you are raising ConnectionRefusedError from socketio.exceptions, not the built in ConnectionRefusedError https://docs.python.org/3/library/exceptions.html#ConnectionRefusedError

from socketio.exceptions import ConnectionRefusedError

or

@sio.event
async def connect(sid, environ):
  raise socketio.exceptions.ConnectionRefusedError("auth failed!")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants