RFC 6455 ëª
ì¸ìì ì ìë íë¡í ì½ì¸ ì¹ìì¼(WebSocket)ì ì¬ì©íë©´ ìë²ì ë¸ë¼ì°ì ê° ì°ê²°ì ì ì§í ìíë¡ ë°ì´í°ë¥¼ êµíí ì ììµëë¤. ì´ë ë°ì´í°ë âí¨í·(packet)â ííë¡ ì ë¬ëë©°, ì ì¡ì 커ë¥ì
ì¤ë¨ê³¼ ì¶ê° HTTP ìì² ìì´ ìë°©í¥ì¼ë¡ ì´ë¤ì§ëë¤.
ì´ë° í¹ì§ ë문ì ì¹ìì¼ì ì¨ë¼ì¸ ê²ìì´ë 주ì í¸ë ì´ë© ìì¤í ê°ì´ ë°ì´í° êµíì´ ì§ìì ì¼ë¡ ì´ë¤ì ¸ì¼ íë ìë¹ì¤ì ì주 ì í©í©ëë¤.
ê°ë¨í ìì
ì¹ìì¼ ì»¤ë¥ì
ì ë§ë¤ë ¤ë©´ new WebSocketì í¸ì¶íë©´ ëëë°, ì´ë wsë¼ë í¹ì íë¡í ì½ì ì¬ì©í©ëë¤.
let socket = new WebSocket("ws://javascript.info");
wsë§ê³ wss://ë¼ë íë¡í ì½ë ìëë°, ë íë¡í ì½ì ê´ê³ë HTTPì HTTPSì ê´ê³ì ì ì¬í©ëë¤.
wss://를 ì¬ì©í©ìë¤.wss://ë ë³´ì ì´ì¸ìë ì 뢰ì±(reliability) 측면ìì wsë³´ë¤ ì¢ ë ì 뢰í ë§í íë¡í ì½ì
ëë¤.
ws://를 ì¬ì©í´ ë°ì´í°ë¥¼ ì ì¡íë©´ ë°ì´í°ê° ìí¸íëì´ìì§ ìì ì±ë¡ ì ì¡ë기 ë문ì ë°ì´í°ê° ê·¸ëë¡ ë
¸ì¶ë©ëë¤. ê·¸ë°ë° ì주 ì¤ëë íë½ì ìë²ë ì¹ìì¼ì´ 무ìì¸ì§ 몰ë¼ì âì´ìíâ í¤ëê° ë¶ì ìì²ì´ ë¤ì´ìë¤ê³ íë¨íê³ ì°ê²°ì ëì´ë²ë¦½ëë¤.
ë°ë©´ wss://ë TSL(ì ì¡ ê³ì¸µ ë³´ì(Transport Layer Security))ì´ë¼ë ë³´ì ê³ì¸µì íµê³¼í´ ì ë¬ëë¯ë¡ ì¡ì ì 측ìì ë°ì´í°ê° ìí¸íëê³ , ë³µí¸íë ìì ì 측ìì ì´ë¤ì§ê² ë©ëë¤. ë°ë¼ì ë°ì´í°ê° ë´ê¸´ í¨í·ì´ ìí¸íë ìíë¡ íë½ì ìë²ë¥¼ íµê³¼íë¯ë¡ íë½ì ìë²ë í¨í· ë´ë¶ë¥¼ ë³¼ ì ìê² ë©ëë¤.
ìì¼ì´ ì ìì ì¼ë¡ ë§ë¤ì´ì§ë©´ ìë ë¤ ê°ì ì´ë²¤í¸ë¥¼ ì¬ì©í ì ìê² ë©ëë¤.
openâ 커ë¥ì ì´ ì ëë¡ ë§ë¤ì´ì¡ì ë ë°ìí¨messageâ ë°ì´í°ë¥¼ ìì íìì ë ë°ìí¨errorâ ìë¬ê° ìê²¼ì ë ë°ìí¨closeâ 커ë¥ì ì´ ì¢ ë£ëìì ë ë°ìí¨
커ë¥ì
ì´ ë§ë¤ì´ì§ ìíìì 무ì¸ê°ë¥¼ ë³´ë´ê³ ì¶ì¼ë©´ socket.send(data)를 ì¬ì©íë©´ ë©ëë¤.
ìì를 ì´í´ë´ ìë¤.
let socket = new WebSocket("wss://javascript.info/article/websocket/demo/hello");
socket.onopen = function(e) {
alert("[open] 커ë¥ì
ì´ ë§ë¤ì´ì¡ìµëë¤.");
alert("ë°ì´í°ë¥¼ ìë²ì ì ì¡í´ë´
ìë¤.");
socket.send("My name is Bora");
};
socket.onmessage = function(event) {
alert(`[message] ìë²ë¡ë¶í° ì ì¡ë°ì ë°ì´í°: ${event.data}`);
};
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]`);
};
ì ììë ë°ëª¨ 목ì ì ìí´ ë§ë¤ì´ëì ê°ì´ Node.js ìë²(server.js)ìì ëìê°ëë¤. ìë²ë 'Hello from server, Boraâë¼ë ë©ìì§ê° ë´ê¸´ ìëµì í´ë¼ì´ì¸í¸ì ë³´ë´ê³ , 5ì´ í 커ë¥ì ì ì¢ ë£ìíµëë¤.
ìë² ìª½ ì½ëê° ëìíë©´ì open â message â close ìì ì´ë²¤í¸ë¥¼ ë³¼ ì ììë ê²ì´ì£ .
ì´ì ì¬ë¬ë¶ì ì¹ìì¼ íµì ì´ ì´ë»ê² ì´ë¤ì§ëì§ë¥¼ ìê² ëì ¨ìµëë¤. ìê°ë³´ë¤ 꽤 ê°ë¨íì£ ?
ì§ê¸ë¶í´ ì¤ë¬´ ìì¤ìì ì¹ìì¼ì íì©í ì ìëë¡ ì¹ìì¼ì ëí´ ì¢ ë ìì¸í ììë´ ìë¤.
ì¹ìì¼ í¸ëì °ì´í¬
new WebSocket(url)ì í¸ì¶í´ ìì¼ì ìì±íë©´ ì¦ì ì°ê²°ì´ ììë©ëë¤.
커ë¥ì ì´ ì ì§ëë ëì, ë¸ë¼ì°ì ë (í¤ë를 ì¬ì©í´) ìë²ì 'ì¹ìì¼ì ì§ìíëì?'ë¼ê³ 물ì´ë´ ëë¤. ì´ì ìë²ê° 'ë¤âë¼ë ìëµì íë©´ ìë²-ë¸ë¼ì°ì ê° íµì ì HTTPê° ìë ì¹ìì¼ íë¡í ì½ì ì¬ì©í´ ì§íë©ëë¤.
ì´ë²ì new WebSocket("wss://javascript.info/chat")ì í¸ì¶í´ ìµì´ ìì²ì ì ì¡íë¤ê³ ê°ì íê³ , ì´ëì ìì² í¤ë를 ì´í´ë´
ìë¤.
GET /chat
Host: javascript.info
Origin: https://javascript.info
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
Sec-WebSocket-Version: 13
Originâ í´ë¼ì´ì¸í¸ ì¤ë¦¬ì§(ììììhttps://javascript.info)ì ëíë ëë¤. ìë²ëOriginí¤ë를 ë³´ê³ ì´ë¤ ì¹ì¬ì´í¸ì ìì¼íµì ì í ì§ ê²°ì í기 ë문ì Origin í¤ëë ì¹ìì¼ íµì ì ì¤ìí ìí ì í©ëë¤. ì°¸ê³ ë¡ ì¹ìì¼ ê°ì²´ë 기본ì ì¼ë¡ í¬ë¡ì¤ ì¤ë¦¬ì§(cross-origin) ìì²ì ì§ìí©ëë¤. ì¹ìì¼ íµì ë§ì ìí ì ì© í¤ëë ì ì½ë ììµëë¤. ì¤ëë ìë²ë ì¹ìì¼ íµì ì ì§ìíì§ ëª»í기 ë문ì ì¹ìì¼ íµì ì í¸íì± ë¬¸ì ë ììµëë¤.Connection: Upgradeâ í´ë¼ì´ì¸í¸ 측ìì íë¡í ì½ì ë°ê¾¸ê³ ì¶ë¤ë ì í¸ë¥¼ ë³´ëë¤ë ê²ì ëíë ëë¤.Upgrade: websocketâ í´ë¼ì´ì¸í¸ì¸¡ìì ìì²í íë¡í ì½ì 'websocketâì´ë¼ë걸 ì미í©ëë¤.Sec-WebSocket-Keyâ ë³´ìì ìí´ ë¸ë¼ì°ì ìì ìì±í í¤ë¡, ìë²ê° ì¹ìì¼ íë¡í ì½ì ì§ìíëì§ë¥¼ íì¸íëë° ì¬ì©ë©ëë¤. Itâs random to prevent proxies from caching any following communication.Sec-WebSocket-Versionâ ì¹ìì¼ íë¡í ì½ ë²ì ì´ ëª ìë©ëë¤. ìììì ë²ì ì 13ì ëë¤.
ë°ëë¼ ìë°ì¤í¬ë¦½í¸ë¡ í¤ë를 ì¤ì íë ê±´ 기본ì ì¼ë¡ ë§íì기 ë문ì XMLHttpRequestë fetchë¡ ì ììì ì ì¬í í¤ë를 ê°ì§ HTTP ìì²ì ë§ë¤ ì ììµëë¤.
ìë²ë í´ë¼ì´ì¸í¸ 측ìì ë³´ë¸ ì¹ìì¼ íµì ìì²ì ìµì´ë¡ ë°ê³ ì´ì ëìíë©´, ìí ì½ë 101ì´ ë´ê¸´ ìëµì í´ë¼ì´ì¸í¸ì ì ì¡í©ëë¤.
101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=
ì¬ê¸°ì Sec-WebSocket-Acceptê°ì í¹ë³í ìê³ ë¦¬ì¦ì ì¬ì©í´ ë§ë Sec-WebSocket-Key ì
ëë¤. ì´ ê°ì ë³´ê³ ë¸ë¼ì°ì ë ìë²ê° ì§ì§ ì¹ìì¼ íë¡í ì½ì ì§ìíëì§ íì¸í©ëë¤.
ì´ë ê² í¸ëì °ì´í¬ê° ëëë©´ HTTP íë¡í ì½ì´ ìë ì¹ìì¼ íë¡í ì½ì ì¬ì©í´ ë°ì´í°ê° ì ì¡ë기 ììí©ëë¤. ì ì¡ì´ ììë íì ì´ë¤ì¼ì´ ì¼ì´ëëì§ë ì¡°ê¸ íì ìì¸í ì´í´ë³´ê² ìµëë¤.
Extensionsì Subprotocols í¤ë
ì¹ìì¼ íµì ì Sec-WebSocket-Extensionsì Sec-WebSocket-Protocol í¤ë를 ì§ìí©ëë¤. ë í¤ëë ê°ê° ì¹ìì¼ íë¡í ì½ ê¸°ë¥ì íì¥(extension)í ëì ìë¸ íë¡í ì½(subprotocal)ì ì¬ì©í´ ë°ì´í°ë¥¼ ì ì¡í ë ì¬ì©í©ëë¤.
ê° í¤ëì ëí ìì를 ì´í´ë´ ìë¤.
-
Sec-WebSocket-Extensions: deflate-frameâ ì´ í¤ëë ë¸ë¼ì°ì ìì ë°ì´í° ìì¶(deflate)ì ì§ìíë¤ë ê²ì ì미í©ëë¤.Sec-WebSocket-Extensionsì ë¸ë¼ì°ì ì ìí´ ìë ìì±ëëë°, ê·¸ ê°ì ë°ì´í° ì ì¡ê³¼ ê´ë ¨ë 무ì¸ê°ë ì¹ìì¼ íë¡í ì½ ê¸°ë¥ íì¥ê³¼ ê´ë ¨ë 무ì¸ê°ê° ëì´ë©ëë¤. -
Sec-WebSocket-Protocol: soap, wampâ ì´ë ê² í¤ëê° ì¤ì ëë©´ íë²í ë°ì´í°ê° ìë SOAPë WAMP(The WebSocket Application Messaging Protocol) íë¡í ì½ì ì¤ìíë ë°ì´í°ë¥¼ ì ì¡íê² ë¤ë ê²ì ì미í©ëë¤. ì¹ìì¼ìì ì§ìíë ìë¸ íë¡í ì½ ëª©ë¡ì IANA ì¹´íë¡ê·¸ìì íì¸í ì ììµëë¤. ê°ë°ìë ì´ í¤ë를 ë³´ê³ ìì¼ë¡ ì¬ì©íê² ë ë°ì´í° í¬ë§·ì íì¸í ì ììµëë¤.ë í¤ëë
new WebSocketì ë ë²ì§¸ 매ê°ë³ìì ê°ì ë£ì´ì ì¤ì í ì ììµëë¤. ìë¸ íë¡í ì½ë¡ SOAPë WAMP를 ì¬ì©íê³ ì¶ë¤ê³ ê°ì í´ ë´ ìë¤. ë ë²ì§¸ 매ê°ë³ìì ë¤ìê³¼ ê°ì´ ë°°ì´ì ë£ì¼ë©´ ë©ëë¤.let socket = new WebSocket("wss://javascript.info/chat", ["soap", "wamp"]);
ì´ë ìë²ë ì§ì ê°ë¥í ìµì¤í ì ê³¼ íë¡í ì½ì ìëµ í¤ëì ë´ì í´ë¼ì´ì¸í¸ì ì ë¬í´ì¼ í©ëë¤.
ìì를 ì´í´ë´ ìë¤. ìì² í¤ëë ë¤ìê³¼ ê°ìµëë¤.
GET /chat
Host: javascript.info
Upgrade: websocket
Connection: Upgrade
Origin: https://javascript.info
Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: deflate-frame
Sec-WebSocket-Protocol: soap, wamp
ì´ë ìë²ê° ë¤ìê³¼ ê°ì ìëµì íë¤ê³ í´ë´ ìë¤.
101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=
Sec-WebSocket-Extensions: deflate-frame
Sec-WebSocket-Protocol: soap
ì´ ê²½ì°, ì°ë¦¬ë ìë²ìì 'deflate-frameâì´ë¼ë ìµì¤í ì ê³¼ ìì² íë¡í ì½ ì¤ SOAPë¼ë ìë¸ íë¡í ì½ë§ ì§ìíë¤ë ì¬ì¤ì ì ì ììµëë¤.
ë°ì´í° ì ì¡
ì¹ìì¼ íµì ì 'íë ì(frame)'ì´ë¼ ë¶ë¦¬ë ë°ì´í° ì¡°ê°ì ì¬ì©í´ ì´ë¤ì§ëë¤. íë ìì ìë²ì í´ë¼ì´ì¸í¸ ì측 모ëìì ë³´ë¼ ì ìëë°, íë ì ë´ ë´ê¸´ ë°ì´í° ì¢ ë¥ì ë°ë¼ ë¤ìê³¼ ê°ì´ ë¶ë¥í ì ììµëë¤.
- í ì¤í¸ íë ì(text frame) â í ì¤í¸ ë°ì´í°ê° ë´ê¸´ íë ì
- ì´ì§ ë°ì´í° íë ì(binary data frame) â ì´ì§ ë°ì´í°ê° ë´ê¸´ íë ì
- í·í íë ì(ping/pong frame) â 커ë¥ì ì´ ì ì§ëê³ ìëì§ íì¸í ë ì¬ì©íë íë ìì¼ë¡ ìë²ë ë¸ë¼ì°ì ìì ìë ìì±í´ì ë³´ë´ë íë ì
- ì´ ì¸ìë 커ë¥ì ì¢ ë£ íë ì(connection close frame) ë± ë¤ìí íë ìì´ ìì
ë¸ë¼ì°ì íê²½ìì ê°ë°ìë í ì¤í¸ë ì´ì§ ë°ì´í° íë ìë§ ë¤ë£¨ê² ë©ëë¤.
ì´ì ë WebSocket .send() ë©ìëë í
ì¤í¸ë ì´ì§ ë°ì´í°ë§ ë³´ë¼ ì ì기 ë문ì
ëë¤.
socket.send(body)를 í¸ì¶í ë, bodyì 문ìì´ì´ë Blob, ArrayBufferë±ì ì´ì§ ë°ì´í°ë§ ë¤ì´ê° ì ììµëë¤. ë°ì´í° ì¢
ë¥ì ë°ë¼ í¹ë³í 무ì¸ê° ì¸í
ì í´ì¤ì¼ í íìë ìê³ , í
ì¤í¸ë ë°ì´ë리 íì
ì ë°ì´í°ë¥¼ ë£ì´ì£¼ë©´ ììì ë°ì´í°ê° ì ì¡ë©ëë¤.
íí¸, ë°ì´í°ë¥¼ ë°ì ë í
ì¤í¸ ë°ì´í°ë íì 문ìì´ ííë¡ ìµëë¤. ì´ì§ ë°ì´í°ë¥¼ ë°ì ëì Blobì´ë ArrayBuffer í¬ë§· ë ì¤ íë를 ê³ ë¥¼ ì ììµëë¤.
socket.binaryType íë¡í¼í°ë¥¼ ì¬ì©íë©´ Blobì´ë ArrayBuffer í¬ë§· ë ì¤ íë를 ê³ ë¥¼ ì ìëë°, íë¡í¼í° 기본ê°ì "blob"ì´ë¼ì ì´ì§ ë°ì´í°ë 기본ì ì¼ë¡ Blob ê°ì²´ ííë¡ ì ì¡ë°ê² ë©ëë¤.
Blobì ê³ ì°¨ì(high-level)ì ì´ì§ ê°ì²´ì¸ë°, <a>ë <img> ë±ì íê·¸ì ë°ë¡ íµí©í ì ìì´ì 기본ê°ì¼ë¡ ì주 ì ì í©ëë¤. íì§ë§ ì´ì§ ë°ì´í°ë¥¼ ì²ë¦¬íë ê³¼ì ì ê°ë³ ë°ì´í° ë°ì´í¸ì ì ê·¼í´ì¼ íë¤ë©´ íë¡í¼í° ê°ì "arraybuffer"ë¡ ë°ê¿ ìë ììµëë¤.
socket.binaryType = "arraybuffer";
socket.onmessage = (event) => {
// event.dataë (í
ì¤í¸ì¸ ê²½ì°) 문ìì´ì´ê±°ë (ì´ì§ ë°ì´í°ì¸ ê²½ì°) arraybuffer ì
ëë¤.
};
ì ì¡ ì í
ë°ì´í° ì ì¡ëì´ ìë¹í ì±ì ê°ë°íê³ ìë¤ê³ ê°ì í´ë´ ìë¤. ê·¸ë°ë° ì°ë¦¬ ì±ì ì¬ì©ìë 모ë°ì¼ì´ë ì골ê°ì´ ë¤í¸ìí¬ ìëê° ë린 ê³³ìì ì±ì ì¬ì©íê³ ìë¤ê³ í´ë³´ì£ .
ì± ìª½ìì socket.send(data)를 ê³ìí´ì í¸ì¶í ì ììµëë¤. íì§ë§ ì´ë ê² íë©´ ë°ì´í°ê° ë©ëª¨ë¦¬ì ìì¼ í
ê³ (ë²í¼) ë¤í¸ìí¬ ìëê° ë°ì´í°ë¥¼ ì¡ì í기ì ì¶©ë¶í ëë§ ì¡ì ë ê²ëë¤.
socket.bufferedAmount íë¡í¼í°ë ì¡ì ë기 ì¤ì¸ íì¬ ìì ìì ì¼ë§ë ë§ì ë°ì´í¸ê° ë©ëª¨ë¦¬ì ìì¬ìëì§ ì 보를 ë´ê³ ììµëë¤.
ë°ë¼ì socket.bufferedAmount íë¡í¼í° ê°ì íì¸íë©´ ìì¼ì ì ì¡ì ì¬ì©í ì ìëì§ ìëì§ë¥¼ íë¨í ì ììµëë¤.
// 100msë§ë¤ ìì¼ì íì¸í´ ìì¬ìë ë°ì´í¸ê° ìë ê²½ì°ìë§
// ë°ì´í°ë¥¼ ì¶ê° ì ì¡í©ëë¤.
setInterval(() => {
if (socket.bufferedAmount == 0) {
socket.send(moreData());
}
}, 100);
커ë¥ì ë«ê¸°
ì°ê²° 주체(ë¸ë¼ì°ì ë ìë²) ì¤ í쪽ìì 커ë·ì ë«ê¸°(close)를 ìíë ê²½ì°ì ë³´íµ ì«ìë¡ ë ì½ëì 문ìë¡ ë ì¬ì ê° ë´ê¸´ '커ë¥ì ì¢ ë£ íë ìâì ì ì¡íê² ë©ëë¤.
ë©ìëë ë¤ìê³¼ ê°ìµëë¤.
socket.close([code], [reason]);
codeâ 커ë¥ì ì ë«ì ë ì¬ì©íë í¹ì ì½ë(ìµì )reasonâ 커ë¥ì ë«ê¸° ì¬ì 를 ì¤ëª íë 문ìì´(ìµì )
ê·¸ë¼ ë¤ë¥¸ í쪽ì 구íë close ì´ë²¤í¸ í¸ë¤ë¬ìì ë¤ìê³¼ ê°ì´ ì½ëì ì¬ì 를 íì¸í ì ììµëë¤.
// ë«ê¸°ë¥¼ ìì²í 주체:
socket.close(1000, "Work complete");
// ë¤ë¥¸ 주체:
socket.onclose = event => {
// event.code === 1000
// event.reason === "ìì
ìë£"
};
ê°ì¥ ë§ì´ ì¬ì©íë ì½ëë ë¤ìê³¼ ê°ìµëë¤.
1000â 기본ê°ì¼ë¡ ì ì ì¢ ë£ë¥¼ ì미í¨(codeê°ì´ 주ì´ì§ì§ ìì ë 기본 ì¸í ë¨)1006â1000ê°ì ì½ë를 ìëì¼ë¡ ì¤ì í ì ìì ë ì¬ì©íê³ , 커ë¥ì ì´ ì ì¤(no close frame)ëììì ì미í¨
ì´ì¸ì ì½ëë ë¤ìê³¼ ê°ìµëë¤.
1001â ì°ê²° 주체 ì¤ íìª½ì´ ë ë¨(ì: ìë² ì §ë¤ì´, ë¶ë¼ì°ì ìì íì´ì§ ì¢ ë£)1009â ë©ìì§ê° ë무 커ì ì²ë¦¬íì§ ëª»í¨1011â ìë² ì¸¡ìì ë¹ì ìì ì¸ ìë¬ ë°ì- â¦ê¸°í ë±ë±â¦
ì½ë ì ì²´ 목ë¡ì RFC6455, §7.4.1ìì íì¸í ì ììµëë¤.
ì¹ìì¼ ì½ëë ì¸ë» 보기ì HTTP ì½ë ê°ì ë³´ì´ì§ë§ ì¤ì ë¡ ë¤ë¦
ëë¤. í¹í 1000ë³´ë¤ ìì ê°ì ìì½ ê°ì´ì¬ì ìì ì«ì를 ì¤ì íë ¤ íë©´ ìë¬ê° ë°ìí©ëë¤.
// ì¬ë¡: 커ë¥í ì ì¤
socket.onclose = event => {
// event.code === 1006
// event.reason === ""
// event.wasClean === false (no closing frame)
};
커ë¥ì ìí
커ë¥ì
ìí를 ìê³ ì¶ë¤ë©´ socket.readyState íë¡í¼í°ì ê°ì íì¸íë©´ ë©ëë¤.
0â âCONNECTINGâ: ì°ê²° ì¤1â âOPENâ: ì°ê²°ì´ ì±ë¦½ëê³ íµì ì¤2â âCLOSINGâ: 커ë¥ì ì¢ ë£ ì¤3â âCLOSEDâ: 커ë¥ì ì´ ì¢ ë£ë¨
ì±í ì± ë§ë¤ê¸°
ë¸ë¼ì°ì ì ì¹ìì¼ APIì Node.jsìì ì ê³µíë ì¹ìì¼ ëª¨ëì ì¬ì©í´ ì±í ì±ì ë§ë¤ì´ë´ ìë¤. ì¬ê¸°ì í´ë¼ì´ì¸í¸(ë¸ë¼ì°ì ) 측ì ì§ì¤í´ì ì±ì ë§ë¤ê±´ë° ìë²ì¸¡ë ì주 ê°ë¨íë ì°¸ê³ í´ì£¼ì¸ì.
HTMLìì ë©ìì§ë¥¼ ë³´ë¼ ë ì¬ì©í <form>ê³¼ ìì ë°ì ë©ìì§ë¥¼ ë³´ì¬ì¤ <div>ê° íìí©ëë¤.
<!-- ë©ìì§ í¼ -->
<form name="publish">
<input type="text" name="message">
<input type="submit" value="ì ì¡">
</form>
<!-- ìì ë°ì ë©ìì§ê° ë
¸ì¶ë div -->
<div id="messages"></div>
ìë°ì¤í¬ë¦½í¸ë¡ ë¤ì ì¸ ê°ì§ 기ë¥ì 구íí´ì¼ í©ëë¤.
- 커ë¥ì ìì±
- form ì ì¶ â
socket.send(message)를 ì¬ì©í´ message ì ì¡ - ë©ìì§ ìì ì²ë¦¬ â ìì í ë©ìì§ë
div#messagesì ì¶ê°
ì½ëë ë¤ìê³¼ ê°ìµëë¤.
let socket = new WebSocket("wss://javascript.info/article/websocket/chat/ws");
// í¼ì ìë ë©ìì§ë¥¼ ì ì¡í©ëë¤.
document.forms.publish.onsubmit = function() {
let outgoingMessage = this.message.value;
socket.send(outgoingMessage);
return false;
};
// ë©ìì§ë¥¼ ìì íê³ , ìì í ë©ìì§ë¥¼ div#messagesì ë³´ì¬ì¤ëë¤.
socket.onmessage = function(event) {
let message = event.data;
let messageElem = document.createElement('div');
messageElem.textContent = message;
document.getElementById('messages').prepend(messageElem);
}
Server-side code is a little bit beyond our scope. Here weâll use Node.js, but you donât have to. Other platforms also have their means to work with WebSocket.
The server-side algorithm will be:
- Create
clients = new Set()â a set of sockets. - For each accepted websocket, add it to the set
clients.add(socket)and setmessageevent listener to get its messages. - When a message is received: iterate over clients and send it to everyone.
- When a connection is closed:
clients.delete(socket).
const ws = new require('ws');
const wss = new ws.Server({noServer: true});
const clients = new Set();
http.createServer((req, res) => {
// here we only handle websocket connections
// in real project we'd have some other code here to handle non-websocket requests
wss.handleUpgrade(req, req.socket, Buffer.alloc(0), onSocketConnect);
});
function onSocketConnect(ws) {
clients.add(ws);
ws.on('message', function(message) {
message = message.slice(0, 50); // max message length will be 50
for(let client of clients) {
client.send(message);
}
});
ws.on('close', function() {
clients.delete(ws);
});
}
Hereâs the working example:
You can also download it (upper-right button in the iframe) and run it locally. Just donât forget to install Node.js and npm install ws before running.
Summary
WebSocket is a modern way to have persistent browser-server connections.
- WebSockets donât have cross-origin limitations.
- They are well-supported in browsers.
- Can send/receive strings and binary data.
The API is simple.
Methods:
socket.send(data),socket.close([code], [reason]).
Events:
open,message,error,close.
WebSocket by itself does not include reconnection, authentication and many other high-level mechanisms. So there are client/server libraries for that, and itâs also possible to implement these capabilities manually.
Sometimes, to integrate WebSocket into existing projects, people run a WebSocket server in parallel with the main HTTP-server, and they share a single database. Requests to WebSocket use wss://ws.site.com, a subdomain that leads to the WebSocket server, while https://site.com goes to the main HTTP-server.
Surely, other ways of integration are also possible.
ëê¸
<code>í그를, ì¬ë¬ ì¤ë¡ 구ì±ë ì½ë를 ì½ì íê³ ì¶ë¤ë©´<pre>í그를 ì´ì©íì¸ì. 10ì¤ ì´ìì ì½ëë plnkr, JSBin, codepen ë±ì ìëë°ì¤ë¥¼ ì¬ì©íì¸ì.