Setting websocket port #6651
-
First check
PortHow to add port in a websocket. I want specifically mention a port in the websocket server. I can specity the port from JS while connecting to a websocket, but can't I do it from the server side. Is there any default value? Can I change that default value? @app.websocket("/ws")
async def websocketEndpoint(websocket: WebSocket):
print("Awaiting clients connection")
await websocket.accept()
while True:
try:
await websocket.receive_text()
resp = {'value': random.uniform(0,1)}
await websocket.send_json(resp)
except Exception as e:
print('error:', e)
break
print("connection ended")Environment
To know the FastAPI version use:
To know the Python version use: |
Beta Was this translation helpful? Give feedback.
Replies: 11 comments
-
|
I think websockets' endpoints run on the same port as your http server, so in JS you specify the same port that you specify when calling |
Beta Was this translation helpful? Give feedback.
-
|
Got it. Is there a way for Server to know that websocket connection is broken or disconnected from client side? |
Beta Was this translation helpful? Give feedback.
-
|
There are |
Beta Was this translation helpful? Give feedback.
-
|
So I am facing this issue. I am not able to add multiple clients to same server with different client Ids My connection manager: I am not able to run a different client with same server. Not sure what I am doing wrong. |
Beta Was this translation helpful? Give feedback.
-
|
@chandu1263 the code you posted is not formatted properly. For multi-line code snippets you should use triple backticks (```) at the beginning and end. |
Beta Was this translation helpful? Give feedback.
-
|
@roveo I formatted it correctly. Can you help me with what I might be doing wrong? |
Beta Was this translation helpful? Give feedback.
-
|
Not sure. I would suggest you test parts of your code separately to make sure they work as intended ( That said, I see several issues with your solution:
or even
|
Beta Was this translation helpful? Give feedback.
-
|
I have modified this accordingly on what you suggested. I added a new class fileListener Then I removed the client_id and connection manager. I also removed the time.sleep() But still I am not able to add more than one client to the server. Second client is waiting for the first client to disconnect. I modified the front end code [ removing the client id] Am I missing some basic async and await functionality. I am still learning about them. So I am kinda confused. |
Beta Was this translation helpful? Give feedback.
-
The way to think about async here is that the second client can connect only while the first endpoint is latest_t, line = fileListener.get_latest()fileListener exists in a separate thread, BUT your main thread is blocked by waiting for the next line to appear. You can avoid this by making your file listener asynchronous. |
Beta Was this translation helpful? Give feedback.
-
|
Here's a working example with just one file per app and so one endpoint. Run this with import asyncio
import sys
import uvicorn
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse
PATH = sys.argv[1]
page = """
<div id="logs">
<ul>
</ul>
</div>
<script>
var ws = new WebSocket("ws://localhost:8000/ws/");
const ul = document.querySelector("#logs > ul");
ws.onmessage = (event) => {
const li = document.createElement("li");
li.innerText = event.data;
ul.appendChild(li);
};
</script>
"""
class Listener:
def __init__(self, path: str, polling_interval: float = 0.5) -> None:
self.path = path
self.pos = 0
self.polling_interval = polling_interval
async def listen(self):
loop = asyncio.get_running_loop()
while True:
lines = await loop.run_in_executor(None, self.poll)
for line in lines:
yield line
await asyncio.sleep(self.polling_interval)
def poll(self):
with open(self.path, "r") as f:
f.seek(self.pos)
lines = f.readlines()
self.pos = f.tell()
return lines
app = FastAPI()
@app.get("/")
def index():
return HTMLResponse(page)
@app.websocket("/ws/")
async def ws(websocket: WebSocket):
await websocket.accept()
port = websocket.client.port
print(f"Client at :{port} connected")
listener = Listener(PATH)
try:
async for line in listener.listen():
await websocket.send_text(line)
except WebSocketDisconnect:
print(f"Client at {port} disconnected")
if __name__ == "__main__":
uvicorn.run(app)
Another thing I noticed is that you open your file only once and not before each polling. I thought it would work, but it doesn't. Apparently, when you call |
Beta Was this translation helpful? Give feedback.
-
|
Thank you so much! I finally able to understand what I was doing wrong. That's a great code and very nice explanation. |
Beta Was this translation helpful? Give feedback.
I think websockets' endpoints run on the same port as your http server, so in JS you specify the same port that you specify when calling
uvicorn.run(or whatever else you're using).