When connecting with HTTP, it is stateless and connectionless. The client can send a request, but the server can't send a response on its own. The server must wait until the client sends a request.
The polling method resolves this issue. It periodically sends a request to check if there is any data the server wants to send or if an event has occurred.
Its con is that it severely increases the HTTP overhead (a phenomenon where process time and memory are additionally used).
Appropriate for:
Works similarly to polling but with an additional condition and settings, where:
Polling keeps sending requests where long polling increases the connection time to wait until an event occurs.
Appropriate for:
Sockets work in TCP and not as HTTP connections. Unlike HTTP, it is stateful and doesn't need to make periodic requests like polling.
The socket is triggered through the Websocket Handshake request to connect from HTTP to Socket.
Either the client or the server can send data.
Appropriate for:
HTML5 standard technology that can send data one-way from the server to the client.
Unlike websockets, a separate protocol is not needed and unlike polling, periodic requests are not needed.
Appropriate for:
WebRTC communicates through P2P. It usually uses UDP and has the advantage of being fast. However, its performance can decrease as users increase as it is P2P.
Appropriate for:
Use the following code to create a websocket. This uses the ws
protocol.
let socket = new WebSocket("ws://localhost");
4 events can be used when the socket is successfully created:
1. open
: Event when connected
2. message
: Event when data is sent
3. error
: Event when error occurs
4. close
: Event when connection is disconnected
Example code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Client</title>
</head>
<body>
<script>
// Websocket handshake
let socket = new WebSocket("wss://javascript.info/article/websocket/demo/hello");
socket.onopen = function(e) {
alert("[open] 커넥션이 만들어졌습니다.");
alert("데이터를 서버에 전송해봅시다.");
// Sends data
socket.send("My name is Bora");
};
socket.onmessage = function(event) {
alert(`[message] 서버로부터 전송받은 데이터: ${event.data}`);
};
// Closes socket
socket.onclose = function(event) {
if (event.wasClean) {
alert(`[close] 커넥션이 정상적으로 종료되었습니다(code=${event.code} reason=${event.reason})`);
} else {
// 예시: 프로세스가 죽거나 네트워크에 장애가 있는 경우
// event.code가 1006이 됩니다.
alert('[close] 커넥션이 죽었습니다.');
}
};
socket.onerror = function(error) {
alert(`[error]`);
};
</script>
</body>
<div id="messages"></div>
</html>
Connection status:
Use socket.readyState
to check the connection status.
0: Connecting
1: Connected
2: Connection closing
3: Connection closed
Server code
const http = require('http');
const fs = require('fs');
const ws = new require('ws');
const wss = new ws.Server({ noServer: true });
const clients = new Set();
function accept(req, res) {
// headers.upgrade (HTTP 1.1 only) is used to upgrade an established server/client connection to a different protocol (websocket)
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Upgrade
// 연결할 때 header에 upgrade가 포함되어있으면, websocket을 쓴다
if (req.url == '/ws' && req.headers.upgrade && req.headers.upgrade.toLowerCase() == 'websocket' && req.headers.connection.match(/\bupgrade\b/i)) {
wss.handleUpgrade(req, req.socket, Buffer.alloc(0), onSocketConnect);
}
else if (req.url == '/') {
// index.html
fs.createReadStream('./index.html').pipe(res);
}
else {
// page not found
res.writeHead(404);
res.end();
}
}
function onSocketConnect(ws) {
clients.add(ws);
console.log(`new connection`);
ws.on('message', function (message) {
const obj = JSON.parse(message);
console.log("message received: ", obj);
// 각각의 클라이언트한테 전달
for (let client of clients) {
// 클라이언트에게 데이터 전송
client.send(JSON.stringify(obj));
}
});
ws.on('close', function () {
console.log(`connection closed`);
// 클라이언트가 종료했으면 배열에서 삭제
clients.delete(ws);
});
}
http.createServer(accept).listen(8080);
The handleUpgrade()
method is a websocket server method used when processing the request to upgrade wss
HTTP. This method is called when the client is upgrading to a different protocol (in this case the websocket protocol) and has this header in the HTTP request.
For the following code
wss.handleUpgrade(req, req.socket, Buffer.alloc(0), onSocketConnect)
Reference: https://github.com/websockets/ws/blob/HEAD/doc/ws.md#serverhandleupgraderequest-socket-head-callback
req
: The client HTTP GET requestreq.socket
: The network socket between the server and clientBuffer.alloc(0)
: Creates a new buffer with a length of 0 bytes. This buffer is used as the websocket data to callback.onSocketConnect
: The callback function that is called when the websocket is connectedClient code
<!-- 메시지 폼 -->
<form name="publish">
<input type="text" name="message">
<input type="submit" value="send">
</form>
<script>
let url ='ws://localhost:8080/ws';
let socket = new WebSocket(url);
// 폼에 있는 메세지 보내기
document.forms.publish.onsubmit = function() {
let outgoingMessage = this.message.value;
const obj = { "type": "message" , "params": { "value": outgoingMessage }}
socket.send(JSON.stringify(obj));
return false;
};
// 들어오는 메세지 핸들링
socket.onmessage = function(event) {
let incomingMessage = event.data;
showMessage(incomingMessage);
};
socket.onclose = event => console.log(`Closed ${event.code}`);
// dev에 메세지 더하기
function showMessage(message) {
let messageElem = document.createElement('div');
const obj = JSON.parse(message);
messageElem.textContent = obj.params.value;
document.getElementById('messages').prepend(messageElem);
}
</script>
<!-- 수신받을 메시지가 노출될 div -->
<div id="messages"></div>
// 해당 이벤트를 받고 콜백함수를 실행
socket.on('받을 이벤트 명', (msg) => {
})
// 이벤트 명을 지정하고 메세지를 보낸다.
socket.emit('전송할 이벤트 명', msg)
// 접속된 모든 클라이언트에게 메시지를 전송한다
io.emit('event_name', msg);
// 메시지를 전송한 클라이언트에게만 메시지를 전송한다
socket.emit('event_name', msg);
// 메시지를 전송한 클라이언트를 제외한 모든 클라이언트에게 메시지를 전송한다
socket.broadcast.emit('event_name', msg);
// 특정 클라이언트에게만 메시지를 전송한다
io.to(id).emit('event_name', data);