본문 바로가기

web

web - 웹소켓 통신을 활용하여 채팅서비스 구현하기

 

 

웹소켓 통신

 

소개

웹소켓(WebSocket)은 실시간 양방향 통신을 위해 개발된 프로토콜이다. 기존의 HTTP 프로토콜은 클라이언트에서 서버로의 단방향 통신을 주로 사용하며, 요청과 응답이 한 쌍을 이룬다. 그러나 웹소켓은 양방향 통신을 지원하여 클라이언트와 서버 간에 지속적인 연결을 유지하고, 실시간으로 데이터를 교환할 수 있다.

 

 

 

http와의 차이

 

HTTP (HyperText Transfer Protocol)

 

  1. 요청-응답 패턴: HTTP는 클라이언트가 서버에 요청을 보내면 서버가 응답을 반환하는 단방향 요청-응답 패턴을 사용한다.
  2. 상태가 없음: HTTP는 상태가 없는(stateless) 프로토콜이므로, 각 요청은 독립적이고 이전 요청과 관련이 없다. 이로 인해 서버는 클라이언트의 상태를 추적하거나 저장하지 않는다.
  3. 헤더 오버헤드: HTTP 요청 및 응답에는 헤더 정보가 포함되어 있으며, 이는 전체 데이터 전송량에 영향을 줄 수 있다.
  4. 적합한 사용 사례: 웹 페이지 요청, API 호출, 파일 다운로드 등 일반적인 웹 통신에 적합하다.

 

웹소켓 통신 (WebSocket)

  1. 양방향 통신: 웹소켓은 클라이언트와 서버 간에 양방향 통신을 가능하게 하며, 한 번 연결이 확립되면 끊어질 때까지 지속된다.
  2. 상태 유지: 웹소켓 연결은 지속적이므로, 클라이언트와 서버 사이의 상태가 유지된다. 이를 통해 실시간 데이터 전송 및 상호작용이 가능하다.
  3. 낮은 오버헤드: 웹소켓 연결이 확립되면, 추가적인 헤더가 거의 필요하지 않으므로 데이터 전송에 대한 오버헤드가 낮다.
  4. 적합한 사용 사례: 실시간 채팅, 온라인 게임, 주식 거래, 실시간 알림 등 실시간 양방향 통신이 필요한 웹 애플리케이션에 적합하다.

 

동작 방식

  1. 클라이언트가 웹소켓 연결 요청을 보낸다. (HTTP 프로토콜을 사용한 핸드셰이크)
  2. 서버는 클라이언트의 요청을 받고, 웹소켓 연결을 수락한다.
  3. 웹소켓 연결이 확립되면, 클라이언트와 서버 간에 양방향 통신이 가능하다.
  4. 원할 때 어느 쪽이든 연결을 종료할 수 있다.

 

특징

  • 실시간 양방향 통신: 웹소켓은 클라이언트와 서버 간의 지속적인 연결을 통해 실시간으로 데이터를 교환할 수 있다.
  • 저 오버헤드: 웹소켓 연결이 확립되면, 데이터를 전송할 때 추가적인 헤더가 거의 필요하지 않으므로 오버헤드가 낮다.
  • 다양한 활용: 웹소켓은 실시간 채팅, 온라인 게임, 주식 거래 등 다양한 분야에서 활용된다.

 

예제

웹소켓을 사용하여 간단한 실시간 채팅 애플리케이션을 만드는 예제를 살펴보자.

 

자바스크립트 코드

// 클라이언트 

const socket = new WebSocket('ws://example.com/socketserver'); 



socket.addEventListener('open', (event) => { 

    socket.send('Hello Server!'); 

}); 



socket.addEventListener('message', (event) => {

    console.log('Message from server: ', event.data); 

});

파이썬 코드

# 서버 (Python - `websockets` 라이브러리 사용) 

import asyncio 

import websockets 



async def handler(websocket, path): 

      message = await websocket.recv()

      print(f"Message from client: {message}”). 



      response = "Hello Client!”

      await websocket.send(response)



start_server = websockets.serve(handler, "localhost", 8765) 



asyncio.get_event_loop().run_until_complete(start_server)

asyncio.get_event_loop().run_forever()

 

 

 

클라이언트 코드 (JavaScript) 설명

 

const socket = new WebSocket('ws://example.com/socketserver');

 

-> 웹소켓 객체를 생성하고, 서버의 웹소켓 주소로 연결을 시도한다.

 

socket.addEventListener('open', (event) => {

 

-> 웹소켓 연결이 열릴 때 호출되는 이벤트 리스너를 등록한다.

 

socket.send('Hello Server!');

 

-> 웹소켓 연결이 성립되면, "Hello Server!" 메시지를 서버에 전송한다.

 

socket.addEventListener('message', (event) => {

 

-> 서버로부터 메시지를 받을 때 호출되는 이벤트 리스너를 등록한다.

 

console.log('Message from server: ', event.data);

 

-> 서버로부터 받은 메시지를 콘솔에 출력한다.

 

 

서버 코드 (Python) 설명

 

mport asyncio

 

-> 비동기 작업을 처리하기 위한 asyncio 라이브러리를 가져온다.

 

import websockets

 

-> 웹소켓 통신을 위한 websockets 라이브러리를 가져온다.

 

async def handler(websocket, path):

 

-> 웹소켓 요청을 처리할 비동기 함수 handler를 정의한다.

 

message = await websocket.recv()

 

-> 클라이언트로부터 메시지를 비동기적으로 수신한다.

 

print(f"Message from client: {message}")

 

-> 받은 메시지를 콘솔에 출력한다.

 

response = "Hello Client!"

 

-> 클라이언트에게 전송할 응답 메시지를 설정한다.

 

await websocket.send(response)

 

-> 응답 메시지를 클라이언트에게 비동기적으로 전송한다.

 

start_server = websockets.serve(handler, "localhost", 8765)

 

-> 서버를 시작하고, 지정된 주소와 포트에서 웹소켓 요청을 수신 대기한다.

 

asyncio.get_event_loop().run_until_complete(start_server)

 

-> 이벤트 루프를 실행하고, 서버가 준비될 때까지 기다린다.

 

asyncio.get_event_loop().run_forever()

 

-> 이벤트 루프를 무한히 실행하여 클라이언트의 요청을 계속 처리한다.

 

 

이 예제에서 클라이언트는 웹소켓을 사용하여 서버와 연결을 맺고, 서버에 메시지를 보낸다. 서버는 클라이언트로부터 메시지를 받아 처리하고, 클라이언트에게 응답을 전송한다. 이를 통해 양방향 통신이 가능해지며, 실시간 채팅 애플리케이션 구현에 활용할 수 있다.

 

웹소켓 통신을 위한 포트 설정 및 주의 사항

 

웹소켓 통신을 사용하는 서비스에서 포트 설정을 고려하는 것은 중요한 사항이다. 여러 사용자가 동시에 서비스에 접속해야 하므로, 웹소켓 서버가 효율적으로 동작하고 모든 사용자의 요청을 처리할 수 있어야 한다. 다음은 서비스에서 고려해야 할 웹소켓 포트 설정에 대한 가이드이다.

 

  1. 포트 선택: 웹소켓 통신을 위한 포트로 일반적으로 사용되는 포트 번호는 80(웹소켓)과 443(웹소켓 보안)이다. 이들 포트는 기본적으로 대부분의 네트워크에서 열려 있으므로, 방화벽이나 다른 네트워크 제한으로 인한 문제를 줄일 수 있다. 그러나 이러한 포트를 사용하기로 결정한 경우, 보안과 관련된 최선의 관행을 따르는 것이 중요하다.
  2. 서버 수 및 로드 밸런싱: 어느 정도 이상의 규모의 서비스에서는 단일 서버로 모든 웹소켓 연결을 처리하기 어려울 수 있다. 이런 경우 여러 웹소켓용 서버를 사용하고 로드 밸런서를 도입하여 서버 간의 트래픽을 분산시킬 수 있다. 로드 밸런서는 클라이언트 요청을 여러 서버에 고르게 분배하여 각 서버의 부하를 최소화하고, 서버 장애 시 다른 서버로 트래픽을 전환하여 높은 가용성을 유지한다.
  3. 포트 개수: 웹소켓 서버의 포트 개수를 결정할 때, 서비스의 사용자 수와 트래픽 패턴을 고려해야 한다. 보통은 하나의 포트만 사용해도 충분하다. 그러나 특정 상황에서 여러 포트를 사용하는 것이 유리할 수 있다. 예를 들어, 서비스에 여러 독립적인 기능이 있고 각 기능에 대해 독립적인 웹소켓 연결을 관리하려면 여러 포트를 사용할 수 있다.

 

일반적으로 중규모 정도의 서비스에서는 기본 웹소켓 포트를 사용하고, 필요에 따라 여러 웹소켓 서버와 로드 밸런서를 도입하여 서버의 부하를 분산시키는 방식이 적합하다. 

 

웹소켓 통신을 위한 서버 설정

 

 

  1. 방화벽 설정: 웹소켓 포트를 사용하려면 해당 포트가 방화벽에서 허용되어야 한다. 이를 위해 방화벽 설정에서 웹소켓 포트를 열어주는 규칙을 추가해야 한다. 방화벽 설정은 시스템 및 네트워크 환경에 따라 다르기 때문에, 사용 중인 환경에 맞는 방화벽 설정 방법을 찾아야 한다.
  2. 포트 포워딩: 웹소켓 서버가 사설 네트워크 내에 있다면, 공인 IP 주소와 사설 IP 주소 간에 포트 포워딩이 필요하다. 이는 공인 IP 주소의 특정 포트로 들어오는 요청을 사설 IP 주소의 웹소켓 서버로 전달해주는 과정이다. 포트 포워딩 설정은 공유기, 라우터, NAT 등의 설정에서 진행할 수 있다.
  3. SSL/TLS 설정: 웹소켓 연결에 보안을 적용하려면 SSL/TLS 인증서를 사용해야 한다. 이를 위해 인증서 발급 기관(CA)에서 인증서를 구입하거나 무료 인증서 발급 서비스인 Let's Encrypt를 사용할 수 있다. 인증서를 적용한 후 웹소켓 서버 설정에서 해당 인증서 파일을 참조하도록 설정한다. 이렇게 하면 웹소켓 보안(WebSocket Secure, wss://)이 적용된다.
  4. CORS 설정: 클라이언트와 웹소켓 서버 간의 도메인이 다른 경우, 웹소켓 연결이 웹 브라우저의 CORS(Cross-Origin Resource Sharing) 정책에 의해 차단될 수 있다. 이를 해결하기 위해 웹소켓 서버에서 CORS 정책을 허용하도록 설정해야 한다. 이 설정은 웹소켓 서버 라이브러리나 프레임워크에 따라 다르므로 해당 문서를 참고해야 한다.

 

이 외에도 웹소켓 서버의 성능 및 안정성을 향상시키기 위해 다양한 최적화 기법을 적용할 수 있다. 하지만 위에서 언급한 사항들은 웹소켓 서비스를 시작하는 데 필수적인 설정이다.

 

 

 

요약

 

웹소켓은 실시간 양방향 통신을 위해 개발된 프로토콜로, 클라이언트와 서버 간에 지속적인 연결을 유지하고, 실시간으로 데이터를 교환할 있다. 웹소켓의 오버헤드와 다양한 활용 가능성 때문에 실시간 채팅, 온라인 게임, 주식 거래 다양한 분야에서 사용된다. 간단한 예제를 통해 웹소켓을 사용하여 실시간 채팅 애플리케이션을 구현하는 방법을 살펴보았다.

'web' 카테고리의 다른 글

web - WebRTC란 무엇인가?  (0) 2023.06.13
web - HTTPS의 동작 방식  (0) 2023.05.04
web - Access Token과 Refresh Token  (0) 2023.05.02
web - CDN(콘텐츠 전송 네트워크)  (0) 2023.05.02
web - JWT  (0) 2023.01.18