R
Railway14mo ago
csd4ni3l

how to use and configure python websockets module and stuff

.
136 Replies
Percy
Percy14mo ago
Project ID: N/A
csd4ni3l
csd4ni3l14mo ago
N/A
Brody
Brody14mo ago
well well well, look what sock the cat dragged in
csd4ni3l
csd4ni3l14mo ago
lmao so you know websockets module right?
luna
luna14mo ago
https://gist.github.com/stefanotorresi/bfb9716f73f172ac4439436456a96d6f Might be a bit out of date but this should be a good read through to work out how it works.
Gist
Playing with Python asyncio and websockets
Playing with Python asyncio and websockets. GitHub Gist: instantly share code, notes, and snippets.
luna
luna14mo ago
If you still need help after that feel free to ask questions.
Brody
Brody14mo ago
i do not i am not a python dev
csd4ni3l
csd4ni3l14mo ago
ok
luna
luna14mo ago
same here. I just help maintain a few python projects.
Brody
Brody14mo ago
ive done websockets in other languaes, so i might not be as usefull as luna, but i still know some stuff
luna
luna14mo ago
Yeah most of my knowledge is in node but websockets are the same at the end of the day no matter the language. Hopefully that gist helps with the syntax.
Brody
Brody14mo ago
websockets 🙂 <wss://utilities.up.railway.app/ws> free clock
csd4ni3l
csd4ni3l14mo ago
wss?
Brody
Brody14mo ago
websockets over https = wss
csd4ni3l
csd4ni3l14mo ago
oh okay
Brody
Brody14mo ago
or is it websockets with tls, idk you get the point
luna
luna14mo ago
Same diff.
Brody
Brody14mo ago
real
csd4ni3l
csd4ni3l14mo ago
would an everytime sending realtime movement and stuff thing would be better or one that only sends if it changes, first one is good when the person has bad internet and data still gets processed
Brody
Brody14mo ago
have a minimum tick time when nothing updates, but also send constantly when positions update? best of both worlds that way you dont use server resources streaming the same data to the clients as fast as your code can
csd4ni3l
csd4ni3l14mo ago
websockets.exceptions.ConnectionClosedOK: received 1000 (OK); then sent 1000 (OK)
luna
luna14mo ago
👀 What’s the question?
Brody
Brody14mo ago
that's not a question
csd4ni3l
csd4ni3l14mo ago
after sending the message to the websocket server i get this error
luna
luna14mo ago
Gonna need more than that. Code sample? Sounds like the connection was opened and then closed?
csd4ni3l
csd4ni3l14mo ago
class Server():
def __init__(self):
self.BUFSIZ = 4096
self.loop = asyncio.get_event_loop()
self.logger = _create_logger()
self.addresses_in_game = {}
self.addresses = {}
self.last_movement_packet = {}
self.email_for_address = {}
self.listen()

def listen(self, host='0.0.0.0', port=port):
self.logger.info("listening on {}:{}".format(host, port))
ws_server = websockets.serve(self.handle_connection, host, port)

self.loop.run_until_complete(ws_server)
self._wake_up_task = asyncio.ensure_future(_wake_up())

try:
self.loop.run_forever()
except KeyboardInterrupt:
self.logger.debug('caught keyboard interrupt')
self.logger.info("exiting")
self._wake_up_task.cancel()
try:
self.loop.run_until_complete(self._wake_up_task)
except asyncio.CancelledError:
self.loop.close()
async def handle_connection(self,client):
"""Sets up handling for incoming clients."""
print("%s:%s has connected." % client.remote_address)
self.addresses[client] = client.remote_address
await self.handle_client(client,client.remote_address)

# Takes client socket as argument.
async def handle_client(self, client, client_address):
"""Handles a single client connection."""
while True:
msg = await client.recv()
if msg != b'':
await self.run_function(client, msg)
else:
await client.close()
break

async def broadcast(self, msg, id_): # prefix is for name identification.
"""Broadcasts a message to all the clients."""

for client in self.player_clients_in_game[str(id_)]:
await client.send(msg.encode())
class Server():
def __init__(self):
self.BUFSIZ = 4096
self.loop = asyncio.get_event_loop()
self.logger = _create_logger()
self.addresses_in_game = {}
self.addresses = {}
self.last_movement_packet = {}
self.email_for_address = {}
self.listen()

def listen(self, host='0.0.0.0', port=port):
self.logger.info("listening on {}:{}".format(host, port))
ws_server = websockets.serve(self.handle_connection, host, port)

self.loop.run_until_complete(ws_server)
self._wake_up_task = asyncio.ensure_future(_wake_up())

try:
self.loop.run_forever()
except KeyboardInterrupt:
self.logger.debug('caught keyboard interrupt')
self.logger.info("exiting")
self._wake_up_task.cancel()
try:
self.loop.run_until_complete(self._wake_up_task)
except asyncio.CancelledError:
self.loop.close()
async def handle_connection(self,client):
"""Sets up handling for incoming clients."""
print("%s:%s has connected." % client.remote_address)
self.addresses[client] = client.remote_address
await self.handle_client(client,client.remote_address)

# Takes client socket as argument.
async def handle_client(self, client, client_address):
"""Handles a single client connection."""
while True:
msg = await client.recv()
if msg != b'':
await self.run_function(client, msg)
else:
await client.close()
break

async def broadcast(self, msg, id_): # prefix is for name identification.
"""Broadcasts a message to all the clients."""

for client in self.player_clients_in_game[str(id_)]:
await client.send(msg.encode())
one sec code block
luna
luna14mo ago
Just a tip at the start use three backticks and then py to make it highlight as python.
csd4ni3l
csd4ni3l14mo ago
async def _wake_up():
while True:
await asyncio.sleep(1)
async def _wake_up():
while True:
await asyncio.sleep(1)
Brody
Brody14mo ago
you instantly close the connection
csd4ni3l
csd4ni3l14mo ago
hm so its not blocking? i thought client.recv is blocking i just remove it then i mean the if statement
Brody
Brody14mo ago
no, you are closing the connection once data is received
csd4ni3l
csd4ni3l14mo ago
oh
Brody
Brody14mo ago
else: client.close
csd4ni3l
csd4ni3l14mo ago
i forgot to use while loop nvm yes i thought its gonna block now fixed thanks going very good
Brody
Brody14mo ago
glad to hear it
csd4ni3l
csd4ni3l14mo ago
server done, i think i can host it on railway rn now i just need to make client work for it
Brody
Brody14mo ago
see, a websocket implantation was super easy
csd4ni3l
csd4ni3l14mo ago
hopefully it will pay out too with the performance because if it doesnt i am lost
Brody
Brody14mo ago
if theres performance issues, it would 100% be on you, not the protocol
csd4ni3l
csd4ni3l14mo ago
ah forgot to delete the port env variable restart works? werent their issues with it or smth? nvm
Brody
Brody14mo ago
what
csd4ni3l
csd4ni3l14mo ago
it auto redeployed it restart on a service deployment but it auto redeployed it so doesnt matter lets see if it works... it worked poggers its using memory again but still not a cpu lol i got charged $0.0001 out of my free kekw
Brody
Brody14mo ago
railway remove free credit when
csd4ni3l
csd4ni3l14mo ago
no no pls no lol
Brody
Brody14mo ago
it would be such a shame if the good actors had to pay their 1-4$ usage
csd4ni3l
csd4ni3l14mo ago
now i just unlock developer plan and it will be very good
Brody
Brody14mo ago
finally, i just went instant for dev without a second thought when i first signed up
csd4ni3l
csd4ni3l14mo ago
checking on usage one sec
csd4ni3l
csd4ni3l14mo ago
csd4ni3l
csd4ni3l14mo ago
ah why its using even a gb of memory?
Brody
Brody14mo ago
don't look at that, that data is unreliable, use the metrics graphs in the service
csd4ni3l
csd4ni3l14mo ago
or is memory calculated from fractions too? ok
Brody
Brody14mo ago
it's a display bug that they haven't fixed in months
csd4ni3l
csd4ni3l14mo ago
brody
csd4ni3l
csd4ni3l14mo ago
csd4ni3l
csd4ni3l14mo ago
then how?
Brody
Brody14mo ago
there you go the metrics graphs in the service itself is accurate, the graphs in the account usage are not accurate, use graphs in the service it's purely a display bug, you won't be charged for 1gb
csd4ni3l
csd4ni3l14mo ago
then how do i know billing? ah okay
Brody
Brody14mo ago
the price estimates should still be relatively accurate, but of course they are only estimates
csd4ni3l
csd4ni3l14mo ago
bruh
csd4ni3l
csd4ni3l14mo ago
csd4ni3l
csd4ni3l14mo ago
lolololol
Brody
Brody14mo ago
it will climb
csd4ni3l
csd4ni3l14mo ago
atleast it works now, i just need to rework and hopefully it will have good performance
Brody
Brody14mo ago
hopefully you wrote efficient code
csd4ni3l
csd4ni3l14mo ago
yes lol one last thing, can you explain what are these Layers and what are their point and how do they work? i never see something like this before i know i am maybe stupid and i just dont know these
Brody
Brody14mo ago
layers?
csd4ni3l
csd4ni3l14mo ago
when you do railway up it sends data to those layers or something
Brody
Brody14mo ago
idk what you are talking about
csd4ni3l
csd4ni3l14mo ago
i heard about deployment layer and network layer
Brody
Brody14mo ago
show example
csd4ni3l
csd4ni3l14mo ago
for example:
csd4ni3l
csd4ni3l14mo ago
csd4ni3l
csd4ni3l14mo ago
"Deployment Layer"
Brody
Brody14mo ago
it just means the part of railways infrastructure that handles the deployments
csd4ni3l
csd4ni3l14mo ago
this?
csd4ni3l
csd4ni3l14mo ago
Brody
Brody14mo ago
that's just pushing the image to railways container registry's so that their orchestrator can run the image
csd4ni3l
csd4ni3l14mo ago
ok @ImLunaHey just one simple question i am using async for the server can i use threading for the client? it would be easier cause i didnt mean to use async everytime and my code is not formatted like async
luna
luna14mo ago
I'd suggest reading https://stackoverflow.com/a/70920890 and the other answers on this page. this is a python specific question and im not that great at python
csd4ni3l
csd4ni3l14mo ago
ok websockets actually fast on localhost, lets try on railway everything is fast on localhost ik but i didnt expect web stuff to do well
Brody
Brody14mo ago
I appreciate the help sock, but if you are going to help you gotta dumb it down for people
csd4ni3l
csd4ni3l14mo ago
lol this is my own ticket, you kekw
Brody
Brody14mo ago
yes I know it is, I'm talking about when you go into other peoples help threads
csd4ni3l
csd4ni3l14mo ago
oh ok
ethan
ethan14mo ago
Not sure if I can bump this or not, but I'm not sure what uri to use for the client to send to would it just be wss:railway-name.up.railway.app:PORT? Ah, I believe it's wss:railway-name.up.railway.app/ws
Brody
Brody14mo ago
if your endpoint is /ws then you would access it over wss://railway-name.up.railway.app/ws
ethan
ethan14mo ago
How would I configure/see the end point? Normally I thought it would be :PORT
Brody
Brody14mo ago
endpoint = the path that you have setup in your code to handle the websocket connection, the endpoint doesnt have anything to do with PORT
ethan
ethan14mo ago
in this case, I believe I'm using localhost
# server.py
import asyncio
import websockets

async def echo(websocket, path):
async for message in websocket:
print(f"Received message: {message}")

start_server = websockets.serve(echo, "localhost")

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
# server.py
import asyncio
import websockets

async def echo(websocket, path):
async for message in websocket:
print(f"Received message: {message}")

start_server = websockets.serve(echo, "localhost")

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
Brody
Brody14mo ago
what route does that handle the websocket connections on
ethan
ethan14mo ago
Not sure
Brody
Brody14mo ago
find out
ethan
ethan14mo ago
Forgive me, but I'm not sure what you mean by route I'm trying to setup a simple script (so it's just server.py right now) to test websockets with Railway
Brody
Brody14mo ago
route / endpoint / path same thing
ethan
ethan14mo ago
test-production-6637.up.railway.app ?
csd4ni3l
csd4ni3l14mo ago
Ethann
Brody
Brody14mo ago
sock, you handle this, i will judge you tho
csd4ni3l
csd4ni3l14mo ago
set a subdomain in the service settings
ethan
ethan14mo ago
:o
Brody
Brody14mo ago
okay stop
csd4ni3l
csd4ni3l14mo ago
Lol
ethan
ethan14mo ago
Custom domain?
Brody
Brody14mo ago
the first thing you said was wrong no, dont listen to what he just said
csd4ni3l
csd4ni3l14mo ago
kekw
ethan
ethan14mo ago
Hahaha okay
Brody
Brody14mo ago
sock, do you want to try again? ethan needs to tell us the endpoint that this code will accept websocket conns on
ethan
ethan14mo ago
Wait, do I have to setup something with flask or django That kinda route? Right now, it's just a python script Was hoping I didn't have to touch flask
Brody
Brody14mo ago
sock, do you use flask? bruh that was a yes or no lol
csd4ni3l
csd4ni3l14mo ago
Yes i used flask before, but he is using websockets so i dont know what flask has to do with this. no if you want just simple sockets but on the web you can use normal websockets Use readthedocs.io for the docs It has tutorials
Brody
Brody14mo ago
you are not too good at helping
ethan
ethan14mo ago
Well the script I'm using is pretty much lifted off the starter docs
csd4ni3l
csd4ni3l14mo ago
The host should be 0.0.0.0 and port should be os.environ['PORT'] for the server on railway but you need to import os module for it. ._.
ethan
ethan14mo ago
From what I read, PORT doesn't have to be configured And I thought 0.0.0.0 is the same as localhost
csd4ni3l
csd4ni3l14mo ago
yes it is i didnt know if you are already using it it is automatically set to a port that is automatically forwarded to your subdomain.up.railway.app website with ssl If you dont set it in service environment variables it will forward and will work
Brody
Brody14mo ago
its not its very much not
csd4ni3l
csd4ni3l14mo ago
Then just use 0.0.0.0 you can just use wss://subdomain.up.railway.app:443 for connecting on client after this and it has ssl configured I go now so i dont say anything stupid, Brody continue or wait for answer
Brody
Brody14mo ago
using wss implies port 443
import os
import asyncio
from websockets.server import serve

async def echo(websocket):
async for message in websocket:
await websocket.send(message)

async def main():
port = os.getenv("PORT", "3000")
async with serve(echo, "0.0.0.0", port):
print(f"running websocket server on port {port}")
await asyncio.Future() # run forever

asyncio.run(main())
import os
import asyncio
from websockets.server import serve

async def echo(websocket):
async for message in websocket:
await websocket.send(message)

async def main():
port = os.getenv("PORT", "3000")
async with serve(echo, "0.0.0.0", port):
print(f"running websocket server on port {port}")
await asyncio.Future() # run forever

asyncio.run(main())
this will run on railway once running on railway you will connect it to with wss://subdomain.up.railway.app
ethan
ethan14mo ago
So if I had set PORT to 8765, then that works as well,right?
Brody
Brody14mo ago
remove that you dont need to specify a PORT in your service variables with the code i provided
ethan
ethan14mo ago
Okay awesome Why is that though? Just because the default is 443 for wss?
Brody
Brody14mo ago
railway will generate a PORT for you
ethan
ethan14mo ago
Okay, then using
async def send_data():
uri = "wss://test-production-6637.up.railway.app/"
async with websockets.connect(uri) as websocket:
sensor_data = {
"temperature": random.uniform(20.0, 25.0),
"humidity": random.uniform(30.0, 40.0),
}
await websocket.send(json.dumps(sensor_data))

asyncio.get_event_loop().run_until_complete(send_data())
async def send_data():
uri = "wss://test-production-6637.up.railway.app/"
async with websockets.connect(uri) as websocket:
sensor_data = {
"temperature": random.uniform(20.0, 25.0),
"humidity": random.uniform(30.0, 40.0),
}
await websocket.send(json.dumps(sensor_data))

asyncio.get_event_loop().run_until_complete(send_data())
Brody
Brody14mo ago
looks like it might work
ethan
ethan14mo ago
Well perhaps I'm doing something wrong, but I see no output in the deploy section No errors either
Brody
Brody14mo ago
do you have a repo?
ethan
ethan14mo ago
yes
Brody
Brody14mo ago
send it over
ethan
ethan14mo ago
GitHub
GitHub - Ethan0429/test: test
test. Contribute to Ethan0429/test development by creating an account on GitHub.
ethan
ethan14mo ago
Oh! Error output finally:
connection handler failed
Traceback (most recent call last):
File "/usr/local/lib/python3.10/site-packages/websockets/legacy/server.py", line 240, in handler
await self.ws_handler(self)
File "/app/test.py", line 8, in echo
await websocket.send(message)
File "/usr/local/lib/python3.10/site-packages/websockets/legacy/protocol.py", line 635, in send
await self.ensure_open()
File "/usr/local/lib/python3.10/site-packages/websockets/legacy/protocol.py", line 944, in ensure_open
raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedOK: received 1000 (OK); then sent 1000 (OK)
connection handler failed
Traceback (most recent call last):
File "/usr/local/lib/python3.10/site-packages/websockets/legacy/server.py", line 240, in handler
await self.ws_handler(self)
File "/app/test.py", line 8, in echo
await websocket.send(message)
File "/usr/local/lib/python3.10/site-packages/websockets/legacy/protocol.py", line 635, in send
await self.ensure_open()
File "/usr/local/lib/python3.10/site-packages/websockets/legacy/protocol.py", line 944, in ensure_open
raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedOK: received 1000 (OK); then sent 1000 (OK)
Okay so it's receiving, but it fails on websocket.send from the server I'm assuming it's failing bc I don't have 2-way channel? Although I though that's what a socket was lmao. I only need the client to send data to the server
Brody
Brody14mo ago
hold your horse delete your Dockerfile rename test.py to main.py add a requirements.txt file with the needed dependencys
ethan
ethan14mo ago
hahaha okay okay Alright, still nothing Im getting this though running websocket server on port 6939
Brody
Brody14mo ago
yeah thats normal
ethan
ethan14mo ago
GOT IT had to use /ws at the end sorry if you specified that already Thank you so much for the spoonfeed
Brody
Brody14mo ago
lmao spoonfeed no worries, we all start somewhere
csd4ni3l
csd4ni3l14mo ago
btw if you ever get this error again it means that the connection got closed like when you use a with statement and it ends