들어가기
현재 진행 중인 사이드 프로젝트 기능 중 오픈채팅방을 구현기능이 있어 WebSocket이란 무엇이고 어떻게 작동하게 되는지에 대하여 기록하기 위한 글입니다.
WebSocket 이란?
HTTP를 통해 실시간 채팅 서비스를 구현한다면 그에 따른 수많은 요청, 응답이 필요하게 됩니다. 이는 클라이언트 측에서 매우 잦은 요청을 하여 클라이언트 측에 부담이 될 뿐 아니라 이를 처리하는 서버도 부하가 생기게 될 것입니다.
이러한 단점을 보완하기 위해 웹 소켓(Web Socket)이 등장하였습니다.웹 소켓 이란 서버와 사용자 간 연결을 "유지"한 상태로 추가 요청 없이 양방향으로 데이터를 교환할 수 있는 프로토콜 입니다.웹 소켓 연결을 만들 때는 WebSocket 생성자를 이용합니다. 이때 매개변수로 url을 전달합니다.
const socket = new WebSocket("wss://example.com");
ws와 wss
웹 소켓의 프로토콜은 ws와 wss 두가지가 있습니다.
ws : 일반적인 웹 소켓 프로토콜
wss : 데이터 보안을 위해 SSL 을 적용한 프로토콜 ws보다 보안과 신뢰성이 더 높음
ws와 wss의 관계는 http와 https의 관계와 비교하면 이해하기 쉽습니다.
웹 소켓 핸드셰이크
핸드셰이크란?
핸드셰이크란 네트워크 분야에서 통신이 시작되기 전 양측 간의 통신을 위해 정보를 교환하는 과정을 의미합니다.
new WebSocket(url)을 호출하여 소켓을 생성하면 즉시 연결이 시작됩니다.
커넥션이 유지 되는동안, 브라우저는 헤더를 사용하여 서버에 웹 소켓을 지원하는지에 대한 여부를 물어봅니다. 이에 서버가 "네" 라는 응답을 하면 서버-브라우저간 통신은 HTTP가 아닌 웹소켓 프로토콜을 사용해 진행됩니다.
클라이언트 측 요청 헤더
GET /chat
Host: javascript.info
Origin: https://javascript.info
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
Sec-WebSocket-Version: 13
- Origin: 클라이언트 오리진을 나타냅니다. 서버는 Origin을 보고 어떤 웹사이트와 소켓통신을 할지 결정합니다.
- Connection: Upgrade - 클라이언트 측에서 프로토콜을 바꾸고 싶다는 신호를 나타냅니다.
- Upgrade: websocket - 클라이언트 측에서 요청한 프로토콜은 websocket 이라는것을 나타냅니다.
- Sec-WebSocket-Key - 보안을 위해 브라우저에서 생성한 키입니다. 서버가 웹소켓을 프로토콜을 지원하는지 확인하는데 사용됩니다.
- Sec-WebSocket-Version: 13 - 웹소켓 프로토콜 버전이 명시됩니다.
서버는 클라이언트 측에서 보낸 웹소켓 통신 요청을 받고 이에 동의하면 상태코드 101이 담긴 응답을 클라이언트에게 전송합니다.
데이터 전송
웹 소켓은 프레임(frame) 라는 데이터 조각을 사용합니다. 프레임은 서버와 클라이언트 양측 모두에서 보낼 수 있습니다.
- 텍스트 프레임 - 텍스트가 담긴 프레임
- 이진 데이터 프레임 - 이진 데이터가 담긴 프레임
- 핑-퐁 프레임 - 커넥션이 유지되고 있는지 확인할 때 사용되는 프레임
- 커넥션 종료 프레임 - 커넥션 종료
데이터는 WebSocket 의 send() 메서드를 통하여 보낼 수 있는데 문자열,Blob,ArrayBuffer등의 이진 데이터만 보낼 수 있습니다.
전송 제한
사용자가 네트워크가 속도가 느린곳에서 웹을 사용한다고 가정하겠습니다. 클라이언트 측에서 계속 send()를 호출하여 데이터를 보낸다면 데이터가 계속 쌓이고 정체될것입니다(Buffer).
socket.bufferAmount 프로퍼티를 사용해 송신 대기 중인 시점에서 얼마나 많은 데이터가 쌓여있는지 확인할 수 있습니다.
커넥션 닫기
서버 또는 클라이언트 중 한쪽에서 커넥션 닫기를 원하는 경우 숫자로 된 코드와 문자로 된 사유가 담긴 커넥션 종료 프레임을 전송합니다.
socket.close([number code],[reason])
// 커넥션 종료를 요청한 측
socket.close(1000,"정상 종료");
// 반대 측
socket.onclose = (event) =>{
console.log(event.code) // 1000
console.log(event.reason) // "정상 종료"
}
가장 많이 사용 되는 코드는 다음과 같습니다
- 1000 - 기본값으로 정상 종료를 의미 (code가 주어지지 않을때 기본값으로 사용됨)
- 1001 - 연결 주체중 한쪽이 떠남
- 1009 - 메시지가 너무 커서 처리하지 못함
- 1011 - 서버 측에서 비정상적인 에러 발생
https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1 해당 링크에서 이외의 코드 확인 가능
커넥션 상태
커넥션 상태를 알고 싶다면 socket.readyState를 사용하여 값을 확인합니다.
- CONNECTING - 연결중
- OPEN - 연결이 성립되고 소통중
- CLOSING - 커넥션 종료중
- CLOSED - 커넥션이 종료됨
웹 소켓 이벤트
웹 소켓이 정상적으로 생성되었다면 4개의 이벤트를 사용 할 수 있습니다.
- open - readyState가 OPEN이 되었을 때 즉 데이터를 주고받을 준비가 되었을 때 발생
- message - 서버로부터 메세지를 받았을 때 발생. 이때 이벤트 객체를 통해 수신된 메세지에 접근 할 수 있음
- error - 에러가 생겼을 때 발생
- close - 커넥션이 종료되었을 때 발생
해당 글은 다음과 같은 출처에서 학습하여 작성된 글입니다.
https://ko.javascript.info/websocket
책 - 기초부터 완성까지, 프런트엔드 : 이재성,한정지음
'FrontEnd' 카테고리의 다른 글
리액트 Stompjs,Sockjs 실시간 채팅 구현 - (1) (0) | 2023.10.16 |
---|---|
프론트엔드 클린코드란?(지극히 주관적) (1) | 2023.10.11 |
FrontEnd - Tailwindcss 동적 스타일링 하기 (0) | 2023.07.27 |
FrontEnd - 재사용성 높인 버튼 공통컴포넌트 만들어보기 with.tailwindcss (0) | 2023.07.09 |
FrontEnd - React-query 를 이용한 무한스크롤 구현하기 - (2) (0) | 2023.07.06 |