728x90
1.웹소켓 (WebSocket)
클라이언트와 서버 간의 양방향 통신을 가능하게 하는 네트워크 프로토콜
HTTP 기반의 초기 연결(handshake)을 설정한 후, 지속적으로 연결을 유지하여 클라이언트와 서버가 실시간으로 데이터를 주고받을 수 있도록 설계한다.
실시간으로 서로 주고받기때문에 채팅, 라이브 스트리밍같은 서비스를 만들때 유용하다.
2.웹소켓 (WebSocket)으로 실시간 채팅만들기
2-1.WebSocket 모듈
FastAPI의 WebSocket 모듈은 실시간 양방향 통신을 구현하기 위해 사용할수있고
비동기식 async/await를 활용한다.
- await websocket.accept(): WebSocket 연결을 수락
- await websocket.receive_text(): 텍스트 메시지를 비동기적으로 수신
- await websocket.send_text(data: str):텍스트 메시지를 비동기적으로 전송
- websocket.close():WebSocket 연결을 종료
2-2. ConnectionManager 클래스
위의 WebSocket 모듈의 메소드를 쉽게 다루기 위해 클래스를 정의해준다.
# 클라이언트를 관리하는 클래스
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_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)
# ConnectionManager 인스턴스를 생성
manager = ConnectionManager()
2-3. 엔드포인트
엔드포인트에 접근되면 클라이언트에서 WebSocket 연결을 서버에 요청받은것이다.
이제 만든 ConnectionManager 의 인스턴스로 연결을 허락해주고 계속해서 클라이언트로부터 메시지를 받게 되면 모든 사용자에게 뿌려준다.
# 웹소켓 엔드포인트 정의
@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: str):
# 새로운 클라이언트 연결을 관리하고, 연결 메시지를 브로드캐스트
await manager.connect(websocket)
await manager.broadcast(f"{client_id}님이 채팅에 참여했습니다.")
try:
while True:
# 클라이언트로부터 메시지를 수신하고, 모든 클라이언트에게 브로드캐스트
data = await websocket.receive_text()
await manager.broadcast(f"{client_id}: {data}")
except WebSocketDisconnect:
# 클라이언트 연결이 끊어지면 관리에서 제거하고, 연결 해제 메시지를 브로드캐스트
manager.disconnect(websocket)
await manager.broadcast(f"{client_id}님이 채팅을 떠났습니다")
2-4. FrontEnd 웹소켓
이제 Client 부분을 웹으로 만들어보자
해당 자바스크립트 코드로 FastAPI 웹소켓에 WebSocket 연결을 요청한다.
const socket = new WebSocket(`ws://localhost:8000/ws/${clientId}`);
그후 메소드들로 다양한 상황을 처리할수있다.
// WebSocket 연결 이벤트
socket.onopen = () => {
appendMessage("서버 접속완료");
};
// 서버에서 메시지를 받을 때
socket.onmessage = (event) => {
appendMessage(event.data);
};
// WebSocket 연결 종료 이벤트
socket.onclose = () => {
appendMessage("서버가 연결안됨 ㅋ");
};
// 폼 제출 이벤트 처리
form.addEventListener("submit", (e) => {
e.preventDefault(); // 폼 기본 동작 막기
const message = messageInput.value.trim();
if (message) {
socket.send(message); // WebSocket으로 메시지 전송
messageInput.value = ""; // 입력창 비우기
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket Chat</title>
<style>
#chatLog div{
margin-top: 5px;
}
</style>
</head>
<body>
<form id="messageForm">
<input type="text" id="messageInput" placeholder="메시지입력">
<button type="submit">Send</button>
</form>
<div id="chatLog"></div>
</body>
<script>
const clientId = "익명"+Date.now();
const socket = new WebSocket(`ws://localhost:8000/ws/${clientId}`);
// HTML 요소 가져오기
const form = document.getElementById("messageForm");
const messageInput = document.getElementById("messageInput");
const chatLog = document.getElementById("chatLog");
// WebSocket 연결 이벤트
socket.onopen = () => {
appendMessage("서버 접속완료");
};
// 서버에서 메시지를 받을 때
socket.onmessage = (event) => {
appendMessage(event.data);
};
// WebSocket 연결 종료 이벤트
socket.onclose = () => {
appendMessage("서버가 연결안됨 ㅋ");
};
// 폼 제출 이벤트 처리
form.addEventListener("submit", (e) => {
e.preventDefault(); // 폼 기본 동작 막기
const message = messageInput.value.trim();
if (message) {
socket.send(message); // WebSocket으로 메시지 전송
messageInput.value = ""; // 입력창 비우기
}
});
// 메시지를 채팅 로그에 추가
function appendMessage(message) {
const messageElement = document.createElement("div");
messageElement.textContent = message;
chatLog.appendChild(messageElement);
}
</script>
</html>
여러 Client가 실시간으로 채팅을 주고받을수있게 만들었다.
728x90
'BackEnd > FastAPI' 카테고리의 다른 글
[FastAPI] Gunicorn, Uvicorn (0) | 2025.01.17 |
---|---|
[FastAPI] Query,Path,Field (1) | 2025.01.03 |
[FastAPI] 요청 본문(Request Body) (0) | 2025.01.03 |