विषय पर बढ़ें

WebSockets

🌐 एआई और मनुष्यों द्वारा किया गया अनुवाद

यह अनुवाद मनुष्यों के मार्गदर्शन में एआई द्वारा किया गया है। 🤝

इसमें मूल अर्थ को गलत समझने या अप्राकृतिक लगने आदि जैसी गलतियाँ हो सकती हैं। 🤖

आप हमें एआई LLM को बेहतर मार्गदर्शन करने में मदद करके इस अनुवाद को बेहतर बना सकते हैं।

अंग्रेज़ी संस्करण

आप FastAPI के साथ WebSockets का उपयोग कर सकते हैं।

websockets install करें

सुनिश्चित करें कि आप एक virtual environment बनाएँ, उसे activate करें, और websockets install करें (एक Python library जो "WebSocket" protocol का उपयोग आसान बनाती है):

$ pip install websockets

---> 100%

WebSockets client

production में

आपके production system में, संभवतः आपके पास React, Vue.js या Angular जैसे आधुनिक framework से बना frontend होगा।

और अपने backend के साथ WebSockets का उपयोग करके संवाद करने के लिए आप संभवतः अपने frontend की utilities का उपयोग करेंगे।

या आपके पास एक native mobile application हो सकती है जो सीधे native code में आपके WebSocket backend से संवाद करती हो।

या आपके पास WebSocket endpoint से संवाद करने का कोई और तरीका हो सकता है।


लेकिन इस उदाहरण के लिए, हम कुछ JavaScript के साथ एक बहुत सरल HTML document का उपयोग करेंगे, सब कुछ एक लंबी string के अंदर।

बेशक, यह optimal नहीं है और आप इसे production के लिए उपयोग नहीं करेंगे।

production में आपके पास ऊपर दिए गए विकल्पों में से एक होगा।

लेकिन WebSockets के server-side पर ध्यान केंद्रित करने और एक working उदाहरण पाने का यह सबसे सरल तरीका है:

from fastapi import FastAPI, WebSocket
from fastapi.responses import HTMLResponse

app = FastAPI()

html = """
<!DOCTYPE html>
<html>
    <head>
        <title>Chat</title>
    </head>
    <body>
        <h1>WebSocket Chat</h1>
        <form action="" onsubmit="sendMessage(event)">
            <input type="text" id="messageText" autocomplete="off"/>
            <button>Send</button>
        </form>
        <ul id='messages'>
        </ul>
        <script>
            var ws = new WebSocket("ws://localhost:8000/ws");
            ws.onmessage = function(event) {
                var messages = document.getElementById('messages')
                var message = document.createElement('li')
                var content = document.createTextNode(event.data)
                message.appendChild(content)
                messages.appendChild(message)
            };
            function sendMessage(event) {
                var input = document.getElementById("messageText")
                ws.send(input.value)
                input.value = ''
                event.preventDefault()
            }
        </script>
    </body>
</html>
"""


@app.get("/")
async def get():
    return HTMLResponse(html)


@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(f"Message text was: {data}")

एक websocket बनाएँ

अपने FastAPI application में, एक websocket बनाएँ:

from fastapi import FastAPI, WebSocket
from fastapi.responses import HTMLResponse

app = FastAPI()

html = """
<!DOCTYPE html>
<html>
    <head>
        <title>Chat</title>
    </head>
    <body>
        <h1>WebSocket Chat</h1>
        <form action="" onsubmit="sendMessage(event)">
            <input type="text" id="messageText" autocomplete="off"/>
            <button>Send</button>
        </form>
        <ul id='messages'>
        </ul>
        <script>
            var ws = new WebSocket("ws://localhost:8000/ws");
            ws.onmessage = function(event) {
                var messages = document.getElementById('messages')
                var message = document.createElement('li')
                var content = document.createTextNode(event.data)
                message.appendChild(content)
                messages.appendChild(message)
            };
            function sendMessage(event) {
                var input = document.getElementById("messageText")
                ws.send(input.value)
                input.value = ''
                event.preventDefault()
            }
        </script>
    </body>
</html>
"""


@app.get("/")
async def get():
    return HTMLResponse(html)


@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(f"Message text was: {data}")

तकनीकी विवरण

आप from starlette.websockets import WebSocket का भी उपयोग कर सकते हैं।

FastAPI वही WebSocket सीधे उपलब्ध कराता है, सिर्फ़ आपकी सुविधा के लिए, developer के रूप में। लेकिन यह सीधे Starlette से आता है।

messages का await करें और messages भेजें

अपने WebSocket route में आप messages के लिए await कर सकते हैं और messages भेज सकते हैं।

from fastapi import FastAPI, WebSocket
from fastapi.responses import HTMLResponse

app = FastAPI()

html = """
<!DOCTYPE html>
<html>
    <head>
        <title>Chat</title>
    </head>
    <body>
        <h1>WebSocket Chat</h1>
        <form action="" onsubmit="sendMessage(event)">
            <input type="text" id="messageText" autocomplete="off"/>
            <button>Send</button>
        </form>
        <ul id='messages'>
        </ul>
        <script>
            var ws = new WebSocket("ws://localhost:8000/ws");
            ws.onmessage = function(event) {
                var messages = document.getElementById('messages')
                var message = document.createElement('li')
                var content = document.createTextNode(event.data)
                message.appendChild(content)
                messages.appendChild(message)
            };
            function sendMessage(event) {
                var input = document.getElementById("messageText")
                ws.send(input.value)
                input.value = ''
                event.preventDefault()
            }
        </script>
    </body>
</html>
"""


@app.get("/")
async def get():
    return HTMLResponse(html)


@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(f"Message text was: {data}")

आप binary, text, और JSON data receive और send कर सकते हैं।

इसे आज़माएँ

अपना code main.py file में रखें और फिर अपना application चलाएँ:

$ fastapi dev

<span style="color: green;">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

अपने browser में http://127.0.0.1:8000 खोलें।

आपको ऐसा एक सरल page दिखेगा:

आप input box में messages टाइप कर सकते हैं, और उन्हें भेज सकते हैं:

और WebSockets के साथ आपका FastAPI application जवाब देगा:

आप कई messages भेज (और receive कर) सकते हैं:

और वे सभी उसी WebSocket connection का उपयोग करेंगे।

Depends और अन्य का उपयोग

WebSocket endpoints में आप fastapi से import कर सकते हैं और उपयोग कर सकते हैं:

  • Depends
  • Security
  • Cookie
  • Header
  • Path
  • Query

वे अन्य FastAPI endpoints/path operations की तरह ही काम करते हैं:

from typing import Annotated

from fastapi import (
    Cookie,
    Depends,
    FastAPI,
    Query,
    WebSocket,
    WebSocketException,
    status,
)
from fastapi.responses import HTMLResponse

app = FastAPI()

html = """
<!DOCTYPE html>
<html>
    <head>
        <title>Chat</title>
    </head>
    <body>
        <h1>WebSocket Chat</h1>
        <form action="" onsubmit="sendMessage(event)">
            <label>Item ID: <input type="text" id="itemId" autocomplete="off" value="foo"/></label>
            <label>Token: <input type="text" id="token" autocomplete="off" value="some-key-token"/></label>
            <button onclick="connect(event)">Connect</button>
            <hr>
            <label>Message: <input type="text" id="messageText" autocomplete="off"/></label>
            <button>Send</button>
        </form>
        <ul id='messages'>
        </ul>
        <script>
        var ws = null;
            function connect(event) {
                var itemId = document.getElementById("itemId")
                var token = document.getElementById("token")
                ws = new WebSocket("ws://localhost:8000/items/" + itemId.value + "/ws?token=" + token.value);
                ws.onmessage = function(event) {
                    var messages = document.getElementById('messages')
                    var message = document.createElement('li')
                    var content = document.createTextNode(event.data)
                    message.appendChild(content)
                    messages.appendChild(message)
                };
                event.preventDefault()
            }
            function sendMessage(event) {
                var input = document.getElementById("messageText")
                ws.send(input.value)
                input.value = ''
                event.preventDefault()
            }
        </script>
    </body>
</html>
"""


@app.get("/")
async def get():
    return HTMLResponse(html)


async def get_cookie_or_token(
    websocket: WebSocket,
    session: Annotated[str | None, Cookie()] = None,
    token: Annotated[str | None, Query()] = None,
):
    if session is None and token is None:
        raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
    return session or token


@app.websocket("/items/{item_id}/ws")
async def websocket_endpoint(
    *,
    websocket: WebSocket,
    item_id: str,
    q: int | None = None,
    cookie_or_token: Annotated[str, Depends(get_cookie_or_token)],
):
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(
            f"Session cookie or query token value is: {cookie_or_token}"
        )
        if q is not None:
            await websocket.send_text(f"Query parameter q is: {q}")
        await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import (
    Cookie,
    Depends,
    FastAPI,
    Query,
    WebSocket,
    WebSocketException,
    status,
)
from fastapi.responses import HTMLResponse

app = FastAPI()

html = """
<!DOCTYPE html>
<html>
    <head>
        <title>Chat</title>
    </head>
    <body>
        <h1>WebSocket Chat</h1>
        <form action="" onsubmit="sendMessage(event)">
            <label>Item ID: <input type="text" id="itemId" autocomplete="off" value="foo"/></label>
            <label>Token: <input type="text" id="token" autocomplete="off" value="some-key-token"/></label>
            <button onclick="connect(event)">Connect</button>
            <hr>
            <label>Message: <input type="text" id="messageText" autocomplete="off"/></label>
            <button>Send</button>
        </form>
        <ul id='messages'>
        </ul>
        <script>
        var ws = null;
            function connect(event) {
                var itemId = document.getElementById("itemId")
                var token = document.getElementById("token")
                ws = new WebSocket("ws://localhost:8000/items/" + itemId.value + "/ws?token=" + token.value);
                ws.onmessage = function(event) {
                    var messages = document.getElementById('messages')
                    var message = document.createElement('li')
                    var content = document.createTextNode(event.data)
                    message.appendChild(content)
                    messages.appendChild(message)
                };
                event.preventDefault()
            }
            function sendMessage(event) {
                var input = document.getElementById("messageText")
                ws.send(input.value)
                input.value = ''
                event.preventDefault()
            }
        </script>
    </body>
</html>
"""


@app.get("/")
async def get():
    return HTMLResponse(html)


async def get_cookie_or_token(
    websocket: WebSocket,
    session: str | None = Cookie(default=None),
    token: str | None = Query(default=None),
):
    if session is None and token is None:
        raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
    return session or token


@app.websocket("/items/{item_id}/ws")
async def websocket_endpoint(
    websocket: WebSocket,
    item_id: str,
    q: int | None = None,
    cookie_or_token: str = Depends(get_cookie_or_token),
):
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(
            f"Session cookie or query token value is: {cookie_or_token}"
        )
        if q is not None:
            await websocket.send_text(f"Query parameter q is: {q}")
        await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")

नोट

क्योंकि यह एक WebSocket है, इसलिए HTTPException raise करना वास्तव में उचित नहीं है, इसके बजाय हम WebSocketException raise करते हैं।

आप specification में परिभाषित valid codes में से एक closing code का उपयोग कर सकते हैं।

dependencies के साथ WebSockets आज़माएँ

अपना application चलाएँ:

$ fastapi dev

<span style="color: green;">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

अपने browser में http://127.0.0.1:8000 खोलें।

वहाँ आप सेट कर सकते हैं:

  • path में उपयोग किया गया "Item ID"।
  • query parameter के रूप में उपयोग किया गया "Token"।

सुझाव

ध्यान दें कि query token को एक dependency द्वारा handle किया जाएगा।

इसके साथ आप WebSocket connect कर सकते हैं और फिर messages भेज और receive कर सकते हैं:

disconnections और कई clients को handle करना

जब WebSocket connection बंद होता है, तो await websocket.receive_text() एक WebSocketDisconnect exception raise करेगा, जिसे आप इस उदाहरण की तरह catch और handle कर सकते हैं।

from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse

app = FastAPI()

html = """
<!DOCTYPE html>
<html>
    <head>
        <title>Chat</title>
    </head>
    <body>
        <h1>WebSocket Chat</h1>
        <h2>Your ID: <span id="ws-id"></span></h2>
        <form action="" onsubmit="sendMessage(event)">
            <input type="text" id="messageText" autocomplete="off"/>
            <button>Send</button>
        </form>
        <ul id='messages'>
        </ul>
        <script>
            var client_id = Date.now()
            document.querySelector("#ws-id").textContent = client_id;
            var ws = new WebSocket(`ws://localhost:8000/ws/${client_id}`);
            ws.onmessage = function(event) {
                var messages = document.getElementById('messages')
                var message = document.createElement('li')
                var content = document.createTextNode(event.data)
                message.appendChild(content)
                messages.appendChild(message)
            };
            function sendMessage(event) {
                var input = document.getElementById("messageText")
                ws.send(input.value)
                input.value = ''
                event.preventDefault()
            }
        </script>
    </body>
</html>
"""


class ConnectionManager:
    def __init__(self):
        self.active_connections: list[WebSocket] = []

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.active_connections.append(websocket)

    def disconnect(self, websocket: WebSocket):
        self.active_connections.remove(websocket)

    async def send_personal_message(self, message: str, websocket: WebSocket):
        await websocket.send_text(message)

    async def broadcast(self, message: str):
        for connection in self.active_connections:
            await connection.send_text(message)


manager = ConnectionManager()


@app.get("/")
async def get():
    return HTMLResponse(html)


@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
    await manager.connect(websocket)
    try:
        while True:
            data = await websocket.receive_text()
            await manager.send_personal_message(f"You wrote: {data}", websocket)
            await manager.broadcast(f"Client #{client_id} says: {data}")
    except WebSocketDisconnect:
        manager.disconnect(websocket)
        await manager.broadcast(f"Client #{client_id} left the chat")

इसे आज़माने के लिए:

  • app को कई browser tabs में खोलें।
  • उनसे messages लिखें।
  • फिर tabs में से एक को बंद करें।

इससे WebSocketDisconnect exception raise होगा, और बाकी सभी clients को ऐसा message मिलेगा:

Client #1596980209979 left the chat

सुझाव

ऊपर दिया गया app एक minimal और सरल उदाहरण है, जो दिखाता है कि कई WebSocket connections को messages कैसे handle और broadcast किए जाएँ।

लेकिन ध्यान रखें कि, चूँकि सब कुछ memory में, एक ही list में handle किया जाता है, यह केवल तब तक काम करेगा जब तक process चल रहा है, और केवल एक single process के साथ काम करेगा।

अगर आपको कुछ ऐसा चाहिए जिसे FastAPI के साथ integrate करना आसान हो लेकिन जो अधिक robust हो, Redis, PostgreSQL या अन्य द्वारा supported हो, तो encode/broadcaster देखें।

अधिक जानकारी

विकल्पों के बारे में अधिक जानने के लिए, इनके लिए Starlette का documentation देखें: