웹소켓(WebSocket) 서론
WebSocket은 브라우저와 서버 간의 양방향 메시지 전송을 가능하게 하는 프로토콜입니다. 웹소켓은 브라우저에서 사용할 수 있는 가장 효과적이고 유연한 통신 수단 중 하나로, 기존 HTTP 인프라와의 상호 운용성을 제공하며, 메시지 중심 통신 및 효율적인 메시지 프레이밍을 통해 클라이언트와 서버 간에 원활한 데이터 스트리밍이 가능합니다.
주요 특징
- 연결 협상 및 동일 출처 정책 시행
- 기존 HTTP 인프라와의 상호 운용성
- 메시지 중심 통신 및 효율적인 메시지 프레이밍
- 서브프로토콜 협상 및 확장성
웹소켓은 간단한 JSON 페이로드부터 사용자 지정 바이너리 메시지 형식까지 클라이언트와 서버 간에 다양한 애플리케이션 프로토콜을 계층화하여 전달할 수 있습니다. 이를 통해 양쪽 모두 언제든지 데이터를 전송할 수 있습니다.
그러나 사용자 정의 프로토콜의 단점은 바로 사용자 정의라는 점입니다. 애플리케이션은 브라우저에서 제공하는 상태 관리, 압축, 캐싱 등의 기능을 고려해야 합니다.
웹소켓을 사용할 때 항상 설계상의 제약과 성능의 절충점이 존재합니다. 최상의 성능을 위해서는 각 프로토콜과 전송 방식의 강점을 활용하는 것이 중요합니다.
결론
웹소켓은 HTTP, XHR, 또는 SSE를 완전히 대체할 수는 없습니다. 오히려, 이 프로토콜들의 강점을 활용하여 웹 애플리케이션의 성능과 사용성을 최적화하는 것이 바람직합니다. 웹소켓은 강력한 통신 도구이지만, 제약 사항과 장단점을 고려하여 적절한 사용이 필요합니다.
웹소켓은 여러 표준의 집합으로, 웹소켓 API는 W3C에서 정의하고 웹소켓 프로토콜(RFC 6455)와 그 확장은 HyBi 워킹 그룹(IETF)에서 정의합니다.
웹소켓 API (WebSocket API)
브라우저에서 직접 제공하는 웹소켓 API는 매우 작고 간단합니다. 연결 관리 및 메시지 처리의 모든 하위 수준 세부사항은 브라우저에서 처리 합니다. 웹소켓 리소스의 URI와 애플리케이션 콜백이 필요한데, 아래 예제에서 코드를 확인할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//1. 새 보안 웹소켓 연결(wss) 열기
const ws = new WebSocket('ws://example.com/socket');
//2. 웹소켓 연결이 설정될 때 호출되는 선택적 콜백
ws.onopen = function () {
ws.send("Hello world"); //3. 클라이언트가 서버로 보내는 메시지
};
//4. 서버에서 새 메시지를 보낼 때마다 호출되는 콜백 함수
ws.onmessage = function(msg) {
if(msg.data instanceof Blob) {
processBlob(msg.data); //5. 수신된 바이너리 메시지 처리 로직 호출
} else {
processText(msg.data); //6. 수신된 텍스트 메시지 처리 로직 호출
}
};
//7. 연결 오류가 발생한 경우 호출되는 선택적 콜백
ws.onerror = function (error) {
...
};
//8. 연결이 종료될 때 호출되는 선택적 콜백
ws.onclose = function () {
...
};
EventSource API와 비슷한 경험을 제공하면서도 웹소켓은 더 다양한 기능을 지원합니다. 이러한 유사성은 웹소켓이 기존 API와 호환성을 유지하면서 확장성을 제공하기 위한 의도적인 설계입니다.
하지만 몇 가지 중요한 차이점이 있습니다.
- 웹소켓은 양방향 통신을 지원하며, 클라이언트와 서버가 서로 메시지를 주고받을 수 있습니다. 반면, EventSource는 서버에서 클라이언트로의 단방향 통신만 지원합니다. 그리고 그 과정에서 서로 다른 프로토콜을 사용합니다.(EventSource Protocol 과 WebSocket Protocol)
- 웹소켓은 텍스트뿐만 아니라 바이너리 데이터도 전송할 수 있습니다. EventSource는 텍스트 데이터만 전송할 수 있습니다.
- WebSocket은 서브프로토콜을 정의할 수 있습니다. 클라이언트와 서버는 이런 사용자 지정 프로토콜을 사용하여 데이터를 주고받을 수 있습니다. 예를 들어, JSON, XML, 또는 protobuf와 같은 데이터 형식을 사용하여 데이터를 전송할 수 있습니다. 또한, 서브 프로토콜을 사용하면, 각각의 특화된 기능을 구현할 수 있습니다.
추가적인 내용은 아래에서 알아보겠습니다.
브라우저의 웹소켓 애뮬레이팅 (Emulating WebSocket In The Browser)
웹소켓 프로토콜은 클라이언트와 서버간 실시간 양방향 통신을 위한 프로토콜입니다. 최신 버전(v13)으로 발전해 모든 브라우저에서 지원되며, 브라우저 지원 상황은 http://caniuse.com/websockets에서 확인 가능합니다.
하지만, 일부 브라우저에서는 웹소켓을 지원하지 않는 경우가 있으므로, 이를 대비하여 에뮬레이션하는 라이브러리가 필요합니다. 하지만, 웹소켓 API를 에뮬레이션하는 라이브러리는 전송에 어려움이 있어 성능에 영향을 미치는 경우가 있습니다.
이를 해결하기 위해 SockJS와 같은 라이브러리는 “seamless fallback”을 가능하게 합니다. 이는 브라우저에서 웹소켓을 지원하지 않는 경우, SockJS가 웹소켓 대신 다른 전송 방법을 사용하여 대체합니다. 이를 통해 브라우저 호환성을 보장하면서도 성능 문제를 해결할 수 있습니다.
또한, Socket.IO와 같은 라이브러리는 고급 기능을 추가로 제공합니다. 이러한 라이브러리를 사용하면 실시간 프레임워크를 쉽게 구현할 수 있으며, 구현과 구성을 최적화하여 성능을 향상시킬 수 있습니다. 이러한 라이브러리는 이벤트 기반 프로그래밍 모델을 제공하여 클라이언트와 서버 간의 통신을 단순화하며, 클라이언트 측에서도 간편하게 구현할 수 있습니다.
따라서, 웹소켓을 이용한 실시간 양방향 통신을 구현하려면 브라우저 호환성을 고려하고, 성능 문제를 해결하기 위해 에뮬레이션하는 라이브러리와 고급 기능을 제공하는 라이브러리를 적절히 선택하여 사용해야 합니다.최상의 성능을 얻기 위해 네이티브 웹소켓 인터페이스를 활용하고, 폴백 전송 성능을 최적화하여 전반적인 통신 성능을 향상시키세요.
WS와 WSS URL 스키마 (WS and WSS URL Schemes)
WebSocket 프로토콜은?
- 웹소켓 프로토콜은 IETF(Internet Engineering Task Force)의 HyBi Working Group에서 제정되었습니다.
- 이 그룹은 브라우저와 서버 간 통신에서 발생하는 문제를 해결하고 최적화된 양방향 통신 채널을 구축하기 위해 웹소켓 프로토콜을 만들었습니다.
- 웹소켓 프로토콜은 브라우저와 서버 간 최적화된 양방향 통신 채널을 구축하기 위해 HTTP 대신 자체 사용자 지정 스키마를 사용합니다.
웹소켓 프로토콜의 URL 스키마
- 일반 텍스트 통신에는 ‘ws’를 사용합니다.
- 암호화된 채널(TCP+TLS)이 필요한 경우에는 ‘wss’를 사용합니다.
웹소켓 프로토콜의 확장성
- 브라우저 외부에서도 비 HTTP 교환을 통해 협상할 수 있도록 확장성을 제공합니다.
- 하지만, 사용자 지정 체계에서는 웹소켓 세션을 설정하기 위한 대체 핸드셰이크 메커니즘에 대한 기존 표준이 없어 추가적인 작업이 필요합니다.
정리 웹소켓 프로토콜은 브라우저와 서버 간 최적화된 양방향 통신 채널을 제공하며, HTTP 대신 자체 사용자 지정 스키마를 사용합니다. 일반 텍스트 통신에는 ‘ws’를 사용하고, 암호화된 채널이 필요한 경우에는 ‘wss’를 사용합니다. 또한, 웹소켓은 브라우저 외부에서도 비 HTTP 교환을 통해 협상할 수 있도록 확장성을 제공하지만, 사용자 지정 체계에서는 추가적인 작업이 필요합니다.
텍스트 및 바이너리 데이터 수신 (Receiving Text and Binary Data By WebSocket)
웹소켓을 사용하여 텍스트와 바이너리 데이터를 효율적으로 전송하고 수신할 수 있습니다.
- 메시지와 애플리케이션 코드 구성
- 웹소켓은 메시지와 애플리케이션 코드로 구성되어 사용자가 데이터의 버퍼링, 구문 분석 및 재구성에 대해 걱정할 필요가 없습니다.
- 데이터 처리의 유연성
- 웹소켓은 텍스트와 바이너리 데이터 모두 처리할 수 있으며, 애플리케이션 페이로드에 대한 제약이나 가정을 두지 않습니다.
- 페이로드 정보 추적
- 웹소켓 프로토콜은 메시지에 대한 두 가지 정보만 추적합니다.
- 페이로드 길이: 가변 길이 필드로서 메시지의 길이를 나타냅니다.
- 페이로드 유형: UTF-8과 바이너리 전송을 구분하기 위한 정보를 포함합니다.
- 웹소켓 프로토콜은 메시지에 대한 두 가지 정보만 추적합니다.
- 데이터 자동 변환 및 전달
- 브라우저가 새 메시지를 수신할 때, 텍스트 기반 데이터는 DOMString 객체로, 바이너리 데이터는 Blob 객체로 자동 변환된 다음 애플리케이션에 전달됩니다.
성능 최적화 옵션
- 수신된 바이너리 데이터를 Blob 대신 ArrayBuffer로 변환하도록 브라우저에 지시함으로써 데이터 처리를 더욱 효율적으로 수행할 수 있습니다.
Blob이란?
- 변경 불가능한 원시 데이터로 구성된 파일과 같은 객체이며 데이터를 수정할 필요가 없고 더 작은 덩어리로 분할할 필요가 없습니다.
- 예: 전체 Blob 객체를 이미지 태그에 전달할 수 있는 경우 최적의 형식(XHR로 데이터 다운로드의 예 참조)
- 반면에 바이너리 데이터에 추가 처리를 수행해야 하는 경우 ArrayBuffer가 더 적합할 수 있습니다.
아래는 성능 최적화 옵션을 사용한 예시입니다.
1
2
3
4
5
6
7
8
9
10
11
const ws = new WebSocket("ws://example.com/socket");
// 바이너리 메시지 수신 시 ArrayBuffer 변환 강제 수행
ws.binaryType = "arraybuffer";
ws.onmessage = function (msg) {
if (msg.data instanceof ArrayBuffer) {
processArrayBuffer(msg.data);
} else {
processText(msg.data);
}
};
User agents는 이 속성을 수신 바이너리 데이터를 처리하는 방법에 대한 힌트로 사용할 수 있습니다. 속성이 “blob”으로 설정되어 있으면 디스크에 스풀링(데이터를 채우는 것)하는 것이 안전하며, “arraybuffer”로 설정되어 있으면 데이터를 메모리에 보관하는 것이 더 효율적일 가능성이 높습니다. 물론 사용자 에이전트는 수신 데이터를 메모리에 보관할지 여부를 결정하기 위해 보다 미묘한 휴리스틱을 사용하도록 권장됩니다.
The WebSocket API, W3C Candidate Recommendation
자바스크립트를 이용한 웹소켓에서 받은 바이너리 데이터 디코딩
예시로 C로 작성된 구조체의 객체를 메시지로 받아 웹소켓에서 디코딩하는 과정을 설명합니다.
먼저, 다음과 같은 C 스타일의 바이너리 데이터 구조를 고려해봅시다.
1
2
3
4
5
6
7
struct personInfo {
char name[20];
unsigned int age;
float height;
};
// 이렇게 할당되어 있다 가정합니다.
struct personInfo person = {"John Doe", 30, 180.5f};
이 구조체는 사람의 정보를 담고 있습니다. 이름은 20바이트의 문자 배열, 나이는 unsigned int 형식, 그리고 키는 float 형식으로 구성되어 있습니다.
웹소켓에서 이벤트를 받으면 다음과 같이 처리할 수 있습니다. 다음 예시처럼 WebSocket은 브라우저 내에서 바이너리 데이터를 처리하는 데 필요한 도구를 애플리케이션에 제공합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
websocket.onmessage = function (event) {
var buffer = event.data;
// TypedArray를 사용한 방식
var nameView = new Uint8Array(buffer, 0, 20);
var ageView = new Uint32Array(buffer, 20, 1);
var heightView = new Float32Array(buffer, 24, 1);
// 출력: Name: John Doe, Age: 30, Height: 180.5
console.log(
"Name: " +
String.fromCharCode.apply(null, nameView) +
", Age: " +
ageView[0] +
", Height: " +
heightView[0]
);
// DataView를 사용한 방식
var dataView = new DataView(buffer);
var name = "";
for (var i = 0; i < 20; i++) {
name += String.fromCharCode(dataView.getUint8(i));
}
var age = dataView.getUint32(20);
var height = dataView.getFloat32(24);
// 출력: Name: John Doe, Age: 30, Height: 180.5
console.log("Name: " + name + ", Age: " + age + ", Height: " + height);
};
위의 예시에서 ArrayBuffer를 각각 TypedArray 방식과 DataView 방식으로 바이너리 데이터를 해독하고 있습니다.
WebSocket텍스트 바이너리 데이터 전송 (Sending Text and Binary Data with WebSocket)
WebSocket을 사용하면 클라이언트와 서버 간에 텍스트 및 바이너리 데이터를 쉽게 주고받을 수 있습니다. WebSocket 프로토콜은 TCP 연결을 통해 양방향 메시지 전달이 가능하게 합니다. 이를 구현하는 과정은 다음과 같습니다.
- WebSocket API 사용 데이터 WebSocket API는 다음과 같은 데이터 유형을 지원합니다.
- UTF-8 인코딩된 문자열
- 바이너리 전송을 위한 ArrayBuffer, ArrayBufferView, Blob 객체
WebSocket 연결 생성 및 데이터 전송 웹 애플리케이션에서 이미지 파일과 텍스트 메시지를 동시에 전송해야 한다고 가정해봅시다.
이 경우 다음과 같이 WebSocket 연결을 생성하고 데이터를 전송할 수 있습니다.1 2 3 4 5 6 7 8 9 10 11 12
const ws = new WebSocket('ws://example.com/socket'); ws.onopen = function () { // 텍스트 메시지 전송 ws.send("Hello!"); // 바이너리 데이터 (예: 이미지 파일) 전송 var buffer = new ArrayBuffer(128); ws.send(buffer); }; ```
- send() 메서드 및 비동기 처리 send() 메서드는 비동기식으로 처리되며, 데이터는 클라이언트에 의해 큐에 대기됩니다.
함수는 즉시 반환되므로 대용량 페이로드 전송 시 전송 완료 신호로 오해하지 않도록 주의해야 합니다. 데이터 양 모니터링 애플리케이션에서는 소켓의 bufferedAmount 속성을 사용하여 브라우저에서 대기 중인 데이터 양을 모니터링할 수 있습니다.
bufferedAmount가 0인 경우에만 send 메서드를 호출하여 데이터를 전송하는 방식도 있습니다. 이렇게 함으로써, 소켓의 대기열에 너무 많은 데이터가 쌓이는 것을 예방할 수 있습니다.다음은 만약 시스템에 업데이트가 발생했다면 서버의 데이터 갱신을 bufferedAmount가 0일 때에만 send를 호출하는 간단한 예제 코드입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
var socket = new WebSocket("ws://example.com"); var updateInterval = 1000; // 1초마다 시스템 업데이트 체크 function checkUpdate() { // 시스템 업데이트 체크 후 업데이트가 있을 경우, 서버에 전송 var updateData = getUpdateData(); // 시스템 업데이트 데이터 가져오기 if (updateData) { socket.send(JSON.stringify(updateData)); // 업데이트 데이터를 JSON 문자열로 변환하여 전송 } } // 일정 주기마다 시스템 업데이트 체크 setInterval(function () { checkUpdate(); }, updateInterval);
위 예제 코드에서 checkUpdate 함수는 일정 주기마다 시스템 업데이트를 체크합니다. 시스템 업데이트가 있을 경우, 해당 업데이트 데이터를 JSON 형태로 변환한 후, WebSocket을 사용하여 서버에 전송합니다.
시스템은 옵저버 패턴 등을 활용해서 더욱 구조적으로 구성할 수도 있습니다.
이렇게 함으로써, 소켓의 대기열에 데이터가 많이 쌓이는 것을 예방하고 HOL 차단 현상을 완화할 수 있습니다. HOL 차단 현상을 완전히 해결하는 것은 아니지만, HOL 차단 현상을 예방하거나 완화하는데에 도움을 줄 수 있습니다.
Head of Line (HOL) 차단 현상 해결 전송을 최적화하려면 각 메시지 유형이 소켓에 대기열에 포함되는 방식과 시기에 세심한 주의를 기울여야 합니다. 이를 통해 Head of Line (HOL) 차단 현상을 해결할 수 있습니다.
1 2 3 4
- 메시지 유형별 대기열 사용: 각 메시지 유형에 대한 대기열을 따로 유지하여, 큰 데이터 덩어리가 전송될 때 작은 데이터 덩어리가 먼저 전송되는 현상을 막을 수 있습니다. 예를 들어, 문자열과 바이너리 데이터를 구분하여 따로 전송하는 것이 좋습니다. - 작은 데이터 덩어리 우선 전송: 큰 데이터 덩어리가 전송될 때는 작은 데이터 덩어리를 먼저 전송하는 것이 좋습니다. 이를 위해서는 메시지 크기를 제한하거나, 메시지가 큰 경우에는 여러 개의 작은 데이터 덩어리로 분할하여 전송하는 방법을 사용할 수 있습니다. - 프로토콜 수준에서 해결: WebSocket 프로토콜 자체에서 HOL 차단 현상을 해결하는 기능을 제공할 수 있습니다. 예를 들어, WebSocket 스펙의 중간에 데이터를 전송할 수 있는 형식인 "Continuation Frames"을 사용하는 것이 좋습니다. 이를 이용하면, 큰 데이터 덩어리를 여러 개의 작은 데이터 덩어리로 분할하여 전송할 수 있으며, 이를 받는 쪽에서는 이들을 조합하여 전체 데이터를 복원할 수 있습니다. - bufferedAmount를 확인하면 HOL를 예방하는 것엔 도움이 됩니다. 하지만 위와 같은 방식을 사용해서 근본적으로 HOL의 문제를 해결하는 것이 좋습니다.
많은 애플리케이션은 제어 트래픽과 같은 우선순위가 높은 업데이트와 백그라운드 전송과 같은 우선순위가 낮은 업데이트 등 여러 클래스의 메시지를 생성합니다.
전송을 최적화하려면 애플리케이션은 각 메시지 유형이 소켓에 대기열에 포함되는 방식과 시기에 세심한 주의를 기울여야 합니다!
서브프로토콜 협상
WebSocket 프로토콜
- 웹소켓 프로토콜은 각 메시지의 형식에 대해 어떠한 가정도 하지 않습니다.
- 단일 비트는 메시지에 텍스트 또는 바이너리 데이터가 포함되어 있는지 여부를 추적해 클라이언트와 서버가 효율적으로 디코딩할 수 있도록 하지만 그렇지 않은 경우 메시지 내용은 불투명합니다.
- 각 요청과 응답의 HTTP 헤더를 통해 추가 메타데이터를 전달하는 HTTP 또는 XHR 요청과 달리 웹소켓 메시지에는 이와 동등한 메커니즘이 없습니다.
- 메시지에 대한 추가 메타데이터가 필요한 경우 클라이언트와 서버가 이런 데이터를 전달하기 위해 자체 서브프로토콜을 구현해야 합니다.
- 클라이언트와 서버는 고정된 메시지 형식에 미리 합의할 수 있습니다.
- 예를 들어, 모든 통신은 JSON 인코딩된 메시지 또는 사용자 정의 바이너리 형식을 통해 이루어지며 필요한 메시지 메타데이터는 인코딩된 구조의 일부 형식 사용합니다.
- 클라이언트와 서버가 서로 다른 데이터 유형을 전송해야 하는 경우 일관된 메시지 헤더를 구성해야 하며, 이를 통해 나머지 페이로드를 디코딩하기 위한 지침을 전달할 수 있습니다.
- 텍스트 메시지와 바이너리 메시지를 혼합하여 페이로드와 메타데이터 정보를 전달할 수 있습니다.
- 예를 들어 텍스트 메시지로 HTTP 헤더에 해당하는 내용을 전달한 다음 바이너리 메시지로 애플리케이션 페이로드를 전달할 수 있습니다.
웹소켓은 메시지의 유연성과 낮은 오버헤드를 제공하지만, 메시지 직렬화와 메타데이터 관리는 문제의 일부입니다. 서로 다른 클라이언트와 서버 간에 동기화를 유지하려면 프로토콜 협상이 필요합니다.
웹소켓은 서브프로토콜 협상 API
를 제공하여 이 문제를 해결합니다. 클라이언트는 초기 연결 핸드셰이크를 통해 어떤 프로토콜을 지원하는지 서버에 알릴 수 있습니다.
이를 통해 클라이언트와 서버는 동일한 프로토콜을 사용하고 메시지 형식 및 메타데이터의 구조를 미리 합의할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
const socket = new WebSocket("ws://example.com/socket", [
"chat",
"notification",
]);
socket.onopen = function () {
if (socket.protocol === "chat") {
// 서버와 클라이언트가 합의한 'chat' 서브프로토콜에 따른 로직 수행
} else if (socket.protocol === "notification") {
// 서버와 클라이언트가 합의한 'notification' 서브프로토콜에 따른 로직 수행
}
};
이 예시에서는 chat
과 notification
두 가지 서브프로토콜을 WebSocket 생성자에 전달합니다. 클라이언트는 초기 핸드셰이크 중에 서버에게 이를 알리며, 서버는 클라이언트가 지정한 서브프로토콜 중 하나를 선택하여 응답합니다.
하위 프로토콜 협상이 성공하면 클라이언트에서 onopen 콜백이 실행되고 WebSocket 객체의 프로토콜 속성을 통해 선택한 프로토콜을 확인할 수 있습니다. 클라이언트와 서버는 이를 통해 메시지의 형식과 메타데이터 구조를 미리 합의할 수 있습니다.
서브프로토콜 이름은 애플리케이션에서 정의되며, 초기 핸드셰이크 중에 클라이언트가 서버에게 전송됩니다. 코어 웹소켓 API에는 서브프로토콜 이름에 대한 특별한 처리 방법이 없으며, 지정된 서브프로토콜은 애플리케이션 로직과 관련된 부분입니다.
선택적으로 onerror를 이용해서 협상에 실패했을 때의 동작을 추가할 수 있습니다.
웹소켓 API를 사용하면 쉽게 웹소켓 연결을 관리하고 메시지를 처리할 수 있으며, 높은 유연성과 확장성을 제공합니다. 이를 통해 실시간 웹 애플리케이션 및 서비스에 최적화된 솔루션을 구현할 수 있습니다. 하지만 다음과 같은 유의사항도 있습니다.
- 웹소켓은 기본적으로 연결 지향형이며, 네트워크 지연이나 연결 손실의 영향을 받을 수 있습니다.
- 웹소켓은 기본적으로 암호화되지 않음. 따라서 중요한 데이터를 전송할 때는 반드시 보안 웹소켓(wss)를 사용해야 합니다.
- 웹소켓은 전통적인 HTTP 프로토콜과는 다르게 작동하므로, 프록시 서버나 방화벽 설정에 주의해야 합니다. 이러한 문제를 해결하기 위해 기존 인프라와 웹소켓이 함께 작동하도록 구성할 수 있습니다.
웹소켓 API는 높은 성능과 실시간 통신 기능을 제공하는 동시에 간단한 인터페이스를 유지합니다. 이를 통해 개발자들은 웹소켓 기반의 다양한 애플리케이션과 서비스를 구축할 수 있으며, 사용자에게 뛰어난 경험을 제공할 수 있습니다. 그러나 이를 사용하기 위해서는 웹소켓의 특성과 제약 사항을 이해하고 적절한 설계 및 구현이 필요합니다.
다음에는 이러한 웹소켓 API가 구현되기 위해 정의된 웹소켓 프로토콜
에 대해 알아보겠습니다.