Socket.IO 는 서버와 클라이언트가 저지연시간, 양방향 및 이벤트 기반 통신을 가능케 하는 라이브러리이다.
WebSocket 프로토콜 위에 구축되었으며, HTTP 롱 폴링으로의 fallback 이나 자동 재연결 같은 추가적인 보증을 제공한다.
> INFO
WebSocket 은 서버와 브라우저간 전이중 통신과 저지연시간 채널을 제공하는 통신 프로토콜이다.
더 많은 정보는 여기서 찾을 수 있다.
이용 가능한 Socket.IO 서버 구현:
그리고 주로 사용하는 언어들의 클라이언트 구현:
WebSocket을 사용한 기본 예제:
서버 (ws 기반)
import { WebSocketServer } from "ws";
const server = new WebSocketServer({ port: 3000 });
server.on("connection", (socket) => {
// send a message to the client
socket.send(JSON.stringify({
type: "hello from server",
content: [ 1, "2" ]
}));
// receive a message from the client
socket.on("message", (data) => {
const packet = JSON.parse(data);
switch (packet.type) {
case "hello from client":
// ...
break;
}
});
});
클라이언트
const socket = new WebSocket("ws://localhost:3000");
socket.addEventListener("open", () => {
// send a message to the server
socket.send(JSON.stringify({
type: "hello from client",
content: [ 3, "4" ]
}));
});
// receive a message from the server
socket.addEventListener("message", ({ data }) => {
const packet = JSON.parse(data);
switch (packet.type) {
case "hello from server":
// ...
break;
}
});
Socket.IO 의 같은 예제:
서버
import { Server } from "socket.io";
const io = new Server(3000);
io.on("connection", (socket) => {
// send a message to the client
socket.emit("hello from server", 1, "2", { 3: Buffer.from([4]) });
// receive a message from the client
socket.on("hello from client", (...args) => {
// ...
});
});
클라이언트
import { io } from "socket.io-client";
const socket = io("ws://localhost:3000");
// send a message to the server
socket.emit("hello from client", 5, "6", { 7: Uint8Array.from([8]) });
// receive a message from the server
socket.on("hello from server", (...args) => {
// ...
});
두 예제는 매우 비슷하게 보이지만 Socket.IO 는 WebSocket 기반으로 작동중인 애플리케이션의 복잡성을 은밀히 숨기는 기능을 제공한다. 이런 기능들은 아래에 리스트 되어있다.
그런데 먼저 Socket.IO 가 아닌 것 부터 확실히 해두자.
> 주의
Socket.IO 는 웹소켓 구현이 아니다.
비록 Socket.IO 가 전송을 위해 가능하면 WebSocket 을 사용하나, 각 패킷에 메타데이터를 추가한다. 이것이 WebSocket 클라이언트가 Socket.IO 서버에 성공적으로 연결할 수 없는 이유이다. Socket.IO 클라이언트도 마찬가지로 보통 WebSocket 서버에 연결할 수 없다.
// 경고: 클라이언트는 연결되지 않을 것!
const socket = io("ws://echo.websocket.org");
WebSocket 서버를 찾고 있다면 ws 나 μWebSocket.js를 참조
Node.js 의 코어에 WebSocket 서버를 포함시킬 것인지에 대한 토론도 있다.
클라이언트 사이드라면 robust-websocket 패키지에도 흥미가 생길 수 있다.
> 주의
Socket.IO 는 모바일 애플리케이션의 백그라운드 서비스에 사용하는 것이 아니다.
Socket.IO 라이브러리는 서버로의 TCP 연결을 계속 열어둔다. 사용자의 배터리를 많이 소비하는 결과로 이어질 수 있다. 이 경우엔 FCM 같은 전용 메시징 플랫폼을 이용하길 바람.
WebSocket 을 통해 Socket.IO 에 의해 제공되는 기능들
WebSocket 연결이 맺어지지 않는 경우 연결이 HTTP long-polling 으로 하위호환 될 수 있다.
이 기능은 생성된지 10년이 넘은(!) 프로젝트에 Socket.IO 를 사용하는 이유 #1 이었다. 당시에는 WebSocket 에 대한 브라우저 지원이 초기단계 였기 때문이다.
현재는 대부분의 브라우저에서 WebSocket 을 지원하더라도 (97% 이상), 잘못 구성된 프록시 때문에 WebSocket 연결이 맺어질 수 없었다는 보고를 사용자로부터 받기 때문에 아직도 대단한 기능이다.
특정한 조건에서 서버와 클라이언트간 WebSocket 연결은 양쪽이 링크의 끊어진 상태를 인식하지 못하는 상태에서 중단될 수 있다.
그래서 Socket.IO는 주기적으로 연결 상태를 확인하는 심박수 메커니즘을 포함하고 있다.
그리고, 결국 클라이언트가 연결이 끊어졌을 때 서버가 먹통이 되지 않기 위해 exponential back-off delay 로 자동으로 다시 연결한다.
클라이언트 연결이 끊어졌을 때 패킷은 자동으로 버퍼링 되어 있다. 그리고 다시 연결 되었을 때 전송될 것이다.
여기서 더 많은 정보 보기
Socket.IO 는 이벤트를 전송하고 응답을 수신하는데 편리한 방법을 제공한다.
송신자
socket.emit("hello", "world", (response) => {
console.log(response); // "got it"
});
수신자
socket.on("hello", (arg, callback) => {
console.log(arg); // "world"
callback("got it");
});
타임아웃도 추가할 수 있다.
socket.timeout(5000).emit("hello", "world", (err, response) => {
if (err) {
// 다른 한 쪽이 딜레이 내에 이벤트를 알아차리지 못함.
} else {
console.log(response); // "got it"
}
});
서버 사이드에서 연결된 모든 클라이언트나 클라이언트의 부분집합에게 이벤트를 전송할 수 있다.
// to all connected clients
io.emit("hello");
// to all connected clients in the "news" room
io.to("news").emit("hello");
다수의 노드로 스케일링(규모를 확장하거나 축소)해도 작동함.
네임스페이스는 단일 공유 연결을 통해 애플리케이션의 로직을 분할시킬 수 있다. 예를 들면 인가된 사용자만 입장할 수 있는 "admin" 채널을 생성하는데 유용하다.
io.on("connection", (socket) => {
// classic users
});
io.of("/admin").on("connection", (socket) => {
// admin users
});
그 이상은 여기서.
웹소켓이 거의 모든 곳에서 지원되기 시작한 현재, 합당한 질문이다.
그 말은 애플리케이션을 위해 WebSocket 만 사용하겠다면 reconnection, acknowledgements, broadcasting 처럼 Socket.IO 에 이미 포함된 대부분의 기능들을 결국 구현해야 한다 (실전 테스트도 된).
socket.emit("hello", "world")
는 42["hello","world"]
를 포함하는 단일 WebSocket 프레임으로 전송 될 것이다.
4
는 Engine.IO "메시지" 패킷 타입이다.2
는 Socket.IO "메시지" 패킷 타입이다.["hello","world"]
는 JSON.stringfy()
된 아규먼트 배열이다.따라서 각 메시지에 대해 몇 추가 바이트가 필요하며, 이는 커스텀 파서를 사용해 더 줄일 수 있다.
> INFO
브라우저 번들 자체의 사이즈는 10.4kB 이다. (minified and gzipped)
트러블 슈팅 가이드 확인