- 클라이언트와 서버 간 양방향 통신을 지원하는 프로토콜
- HTTP 요청과 다르게 한 번 연결되면 지속적으로 데이터 송수신 가능
- 클라이언트가 요청하지 않아도 서버가 데이터를 보낼 수 있음 (Push
방식 지원)- ws:// 또는 wss://(보안) 방식 활용(web socket security)
- 실시간 통신
= 기존 HTTP 방식의 문제점
특징 | HTTP | WebSocket |
---|---|---|
연결 방식 | 요청-응답 방식 | 지속적인 연결 유지 |
통신 방식 | 클라이언트가 요청하면 서버가 응답 | 서버와 클라이언트가 자유롭게 송수신 가능 |
활용 사례 | REST API, 정적 페이지 요청 | 실시간 채팅, 알림 시스템, 주식 데이터 스트리밍 |
pip3 install 'uvicorn[standard]'
from fastapi import FastAPI, WebSocket
app = FastAPI()
@app.websocket("/ws") # 보편적으로 /ws로 url을 지정
async def websocket_endpoint(websocket: WebSocket): # 실시간으로 여러 요청을 처리하기에 비동기가 적합
await websocket.accept() # WebSocket 연결 수락
while True: 서버를 게속 유지하기위해 (돌리기 위해)
data = await websocket.receive_text() # 클라이언트 메세지 수신
await websocket.send_text(f"서버 응답: {data}") # 클라이언트에게 응답
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
app = FastAPI()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
try:
while True:
data = await websocket.receive_text()
await websocket.send_text(f"서버 응답 : {data}")
except WebSocketDisconnect:
print("클라이언트 연결 종료")
- 대표적인 서비스 사례
- 실시간 채팅: 카카오톡, 슬랙, 디스코드 등
- 실시간 알림 시스템: SNS 알림, 주문 처리 상태 알림 등
- 실시간 주식 데이터 스트리밍: 증권 거래소 API
- 실시간 협업 기능: Google Docs같은 실시간 편집
class ConnectionManager:
"""WebSocket 연결관리"""
def __init__(self): # 연결된 사용자 리스트
self.active_connections: List[WebSocket] = []
async def connect(self, websocket: WebSocket):
""" 클라이언트가 websocket 연결을 요청하면 리스트에 추가 """
await websocket.accept()
self.active_connections.append(websocket)
def disconnect(self, websocket: WebSocket):
self.active_connections.remove(websocket)
async def broadcast(self, message: str):
""" 모든 연결된 클라이언트에게 메세지 전송 """
for connection in self.active_connections:
await connection.send_text(message)
manager = ConnectionManager()
# 특정 요청을 감지하면 서버가 사용자에게 전달
from typing import Dict, List
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
app = FastAPI()
class ConnectionManager:
def __init__(self):
self.active_connections: Dict[str, WebSocket] = {}
async def connect(self, websocket: WebSocket, username: str):
""" 특정 사용자의 WebSocket 연결 관리 """
await websocket.accept()
self.active_connections[username] = websocket
def disconnect(self, username: str):
""" 사용자가 연결을 끊으면 제거 """
if username in self.active_connections:
del self.active_connections[username]
async def send_private_message(self, username: str, message: str):
""" 특정 사용자에게 메세지 전송 """
if username in self.active_connections:
await self.active_connections[username].send_text(message)
manager = ConnectionManager()
@app.websocket("/ws/{username}")
async def websocket_endpoint(username: str,websocket: WebSocket):
""" 클라이언트가 /ws 경로로 WebSocket 연결 요청 """
await manager.connect(websocket, username)
try:
while True:
data = await websocket.receive_text()
await manager.send_private_message(username, f"📢 개인 메시지: {data}")
except WebSocketDisconnect:
manager.disconnect(username)
@app.post("/send-message/{username}")
async def send_message(username: str, message: str):
""" 특정 사용자에게 메시지를 전송하는 API (Postman 테스트용) """
await manager.send_private_message(username, message)
return {"message": f"📢 {username}에게 메시지 전송 완료!"}
while Ture:
await websocket.send_text("ping")
await asyncio.sleep(30) # 30초마다 ping 전송