λ„€νŠΈμ›Œν¬

WebSocketμ΄λž€? κ°œλ…κ³Ό λ™μž‘ κ³Όμ • (+socket.io, Polling, Streaming...)

doozi 2022. 7. 27. 16:39

πŸ“’ λ“€μ–΄κ°€λ©°

직μž₯μ—μ„œ μžλ™ μ—…λ°μ΄νŠΈ κΈ°λŠ₯을 κ΅¬ν˜„ν•  일이 생겼닀.
λˆ„κ΅°κ°€ μ›Ήμ˜ 데이터λ₯Ό μˆ˜μ •ν–ˆμ„ λ•Œ
λ‹€λ₯Έ PCλ₯Ό μ‚¬μš© 쀑인 μ‚¬λžŒμ˜ 화면에도 ν•΄λ‹Ή 데이터가 μžλ™μœΌλ‘œ μ‹€μ‹œκ°„ μ—…λ°μ΄νŠΈ λ˜κ²Œν•˜λŠ” κΈ°λŠ₯μ΄μ—ˆλ‹€.

 

λ‚˜λŠ” 이 κΈ°λŠ₯을 κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄ 5μ΄ˆλ§ˆλ‹€ ν•œλ²ˆ μ”© λ°μ΄ν„°μ˜ μˆ˜μ •λœ μ‹œκ°„λ₯Ό DBμ—μ„œ κ°€μ Έμ™”κ³ ,
DBμ—μ„œ κ°€μ Έμ˜¨ μˆ˜μ •λœ μ‹œκ°„μ΄ κΈ°μ‘΄ μˆ˜μ •λœ μ‹œκ°„κ³Ό λ‹€λ₯΄λ‹€λ©΄ 화면이 refresh λ˜λ„λ‘ κ΅¬ν˜„ν–ˆλ‹€.
(κ΅¬ν˜„ν•  땐 λͺ°λžλŠ”λ°, μ΄λ ‡κ²Œ 일정 주기둜 ν†΅μ‹ ν•˜μ—¬ κ°€μ Έμ˜€λŠ” 방법을 Polling 이라고 ν•œλ‹¨λ‹€.)

 

그런데 λŒ€λ¦¬λ‹˜κ»˜μ„œ μ΄λ ‡κ²Œ ν•˜λŠ” 것도 ν‹€λ¦° 건 μ•„λ‹ˆμ§€λ§Œ μ›Ή μ†ŒμΌ“μ„ μ‚¬μš©ν•˜λŠ” 방법이 μžˆλ‹€κ³  말씀해주셨닀.
λ‚˜λŠ” μ›Ή μ†ŒμΌ“μ— λŒ€ν•΄ μ „ν˜€ μ•Œμ§€ λͺ»ν–ˆλ‹€...
κ·Έλž˜μ„œ λΆ€λž΄λΆ€λž΄ κ³΅λΆ€ν•˜κ³  Polling λ°©μ‹μœΌλ‘œ κ΅¬ν˜„λœ μ½”λ“œλ₯Ό μ›Ή μ†ŒμΌ“ λ°©μ‹μœΌλ‘œ λ³€κ²½ν–ˆλ‹€!

 

이번 ν¬μŠ€νŒ…μ—μ„  κ³΅λΆ€ν–ˆλ˜ μ›Ή μ†ŒμΌ“μ— λŒ€ν•΄μ„œ 정리해 λ³Ό 것이닀.

⚑ μ›Ή μ†ŒμΌ“

μ„œλ²„μ™€ ν΄λΌμ΄μ–ΈνŠΈ κ°„μ˜ λ©”μ‹œμ§€ κ΅ν™˜μ„ μœ„ν•œ 톡신 κ·œμ•½(ν”„λ‘œν† μ½œ)

⚑ μ›Ή μ†ŒμΌ“μ˜ νŠΉμ§•

μ–‘λ°©ν–₯ 톡신 (Full-Duplex)

데이터 μ†‘μˆ˜μ‹ μ„ λ™μ‹œμ—! μ²˜λ¦¬ν•  수 μžˆλŠ” 방법.
톡상적인 HTTP 톡신은 client κ°€ μš”μ²­μ„ λ³΄λ‚΄λŠ” κ²½μš°μ—λ§Œ Serverκ°€ 응닡을 ν•˜λŠ” 단방ν–₯ ν†΅μ‹ μ΄μ§€λ§Œ,
μ›Ή μ†ŒμΌ“μ€ μ–‘λ°©ν–₯ 톡신이 κ°€λŠ₯ν•˜λ‹€.

μ‹€μ‹œκ°„ λ„€νŠΈμ›Œν‚Ή (Real Time Networking)

μ›Ή ν™˜κ²½μ—μ„œ μ—°μ†λœ 데이터λ₯Ό λΉ λ₯΄κ²Œ λ…ΈμΆœν•˜λŠ” 것.
ex. μ±„νŒ…, 주식

⚑ μ›Ή μ†ŒμΌ“μ΄ λ‚˜μ˜€κΈ° μ „κΉŒμ§€μ˜ 톡신 방식

μ›Ή μ†ŒμΌ“μ΄ λ‚˜μ˜€κΈ° μ „,
μ–‘λ°©ν–₯ 톡신과 μ‹€μ‹œκ°„ λ„€νŠΈμ›Œν‚Ήμ„ κ°€λŠ₯ν•˜κ²Œ ν–ˆλ˜ 방법듀을 μ•Œμ•„λ³΄μž.

Polling

πŸ“’ λ“€μ–΄κ°€λ©° λΆ€λΆ„μ—μ„œ μ–ΈκΈ‰ν–ˆλ˜ λ‚΄κ°€ μ΄ˆκΈ°μ— κ΅¬ν˜„ν•œ 방식이닀.


μΌμ •ν•œ 주기둜 μ„œλ²„μ— μš”μ²­(Request)을 λ³΄λ‚΄λŠ” 방법.
setTimeout, setInterval λ“±μœΌλ‘œ 일정 μ£ΌκΈ°λ§ˆλ‹€ μ„œλ²„μ— μš”μ²­(Request)을 보내면 λœλ‹€.
(λ‚˜λŠ” setInterval을 μ‚¬μš©ν–ˆμ—ˆλ‹€.)

 

λΆˆν•„μš”ν•œ Request 와 Connection을 μƒμ„±ν•˜μ—¬ μ„œλ²„μ— 뢀담을 μ£Όκ²Œλœλ‹€.
μš”μ²­ μ£ΌκΈ°κ°€ 짧을 수둝 λΆ€ν•˜κ°€ 컀진닀.
'일정 μ£ΌκΈ°λ§ˆλ‹€' μš”μ²­μ„ λ³΄λ‚΄λŠ” 것이기 λ•Œλ¬Έμ— μ‹€μ‹œκ°„μ΄λΌκ³  보기에 μ• λ§€ν•˜λ‹€.
μš”μ²­ μ£ΌκΈ°κ°€ 짧으면 μ‹€μ‹œκ°„ 처럼 λ³΄μ΄κ² μ§€λ§Œ, μ‹€μ œλ‘œ μ‹€μ‹œκ°„μ€ μ•„λ‹ˆλ‹€.
HTTP 톡신을 ν•˜κΈ° λ•Œλ¬Έμ— Request, Response 헀더가 λΆˆν•„μš”ν•˜κ²Œ 크닀.

  • Polling 방식을 μ„ νƒν•˜λŠ” 경우
    • 응닡을 μ‹€μ‹œκ°„μœΌλ‘œ λ°›μ§€ μ•Šμ•„λ„ λ˜λŠ” 경우
    • λ‹€μˆ˜μ˜ μ‚¬μš©μžκ°€ λ™μ‹œμ— μ‚¬μš©ν•˜λŠ” 경우
    • ex. facebook μ›Ή μ±„νŒ…, google λ©”μ‹ μ €, msn μ›Ή λ©”μ‹ μ €

Long Polling

Pollingκ³Ό λΉ„μŠ·ν•˜κ²Œ 일정 μ£ΌκΈ°λ§ˆλ‹€ μš”μ²­μ„ λ³΄λ‚΄μ§€λ§Œ μ„œλ²„κ°€ 응닡을 λ°”λ‘œ μ „λ‹¬ν•˜μ§€ μ•ŠλŠ” 방식이닀.
μš”μ²­μ„ λ³΄λƒˆμ„ λ•Œ, μ„œλ²„κ°€ 응닡을 λ°”λ‘œ 보내지 μ•Šκ³  νŠΉμ • μ΄λ²€νŠΈλ‚˜ νƒ€μž„μ•„μ›ƒμ΄ λ°œμƒν–ˆμ„ λ•Œ 응닡을 μ „λ‹¬ν•˜λŠ” 방식.
응닡을 받은 ν΄λΌμ΄μ–ΈνŠΈλŠ” λ‹€μ‹œ μ„œλ²„μ— 데이터λ₯Ό μš”μ²­ν•œλ‹€.

 

λΆˆν•„μš”ν•œ μš”μ²­μ„ 보내지 μ•Šμ•„ Polling 보닀 μ’‹μ•„λ³΄μ΄μ§€λ§Œ,
Long Polling 도 λ™μ‹œ λ‹€λ°œμ μΈ μš”μ²­κ³Ό 응닡이 생기면 λΆ€ν•˜κ°€ λ°œμƒν•  수 μžˆλ‹€.
HTTP 톡신을 ν•˜κΈ° λ•Œλ¬Έμ— Request, Response 헀더가 λΆˆν•„μš”ν•˜κ²Œ 크닀.

  • Long Polling 방식을 μ„ νƒν•˜λŠ” 경우
    • 응닡을 μ‹€μ‹œκ°„μœΌλ‘œ λ°›μ•„μ•Όν•˜λŠ” 경우
    • 적은 수의 μ‚¬μš©μžκ°€ λ™μ‹œμ— μ‚¬μš©ν•˜λŠ” 경우

Streaming

μ΄λ²€νŠΈκ°€ λ°œμƒν–ˆμ„ λ•Œ 응닡을 λ‚΄λ €μ£Όλ˜, 응닡을 μ™„λ£Œμ‹œν‚€μ§€ μ•Šκ³  계속 연결을 μœ μ§€ν•˜λŠ” 방식.

 

Long Polling에 λΉ„ν•΄ μ‘λ‹΅λ§ˆλ‹€ λ‹€μ‹œ μš”μ²­μ„ ν•˜μ§€ μ•Šμ•„λ„ λ˜λ―€λ‘œ νš¨μœ¨μ μ΄μ§€λ§Œ,
μ—°κ²° μ‹œκ°„μ΄ κΈΈμ–΄μ§ˆ 수둝 μ—°κ²° μœ νš¨μ„± κ΄€λ¦¬μ˜ 뢀담이 λ°œμƒν•œλ‹€.
HTTP 톡신을 ν•˜κΈ° λ•Œλ¬Έμ— Request, Response 헀더가 λΆˆν•„μš”ν•˜κ²Œ 크닀.

⚑ μ›Ή μ†ŒμΌ“ λ™μž‘ κ³Όμ •

μ›Ή μ†ŒμΌ“ λ™μž‘ 과정은 크게 μ„Έκ°€μ§€λ‘œ λ‚˜λˆŒ 수 μžˆλ‹€.

μœ„ μ΄λ―Έμ§€μ˜ λΉ¨κ°„ 색 λ°•μŠ€μ— ν•΄λ‹Ήν•˜λŠ” Opening Handshake
μœ„ μ΄λ―Έμ§€μ˜ λ…Έλž€ 색 λ°•μŠ€μ— ν•΄λ‹Ήν•˜λŠ” Data transfer
μœ„ μ΄λ―Έμ§€μ˜ 보라 색 λ°•μŠ€μ— ν•΄λ‹Ήν•˜λŠ” Closing Handshake

🀝 Handshake

Opening Handshake 와 Closing Handshake λŠ” 일반적인 HTTP TCP ν†΅μ‹ μ˜ κ³Όμ • 쀑 ν•˜λ‚˜μ΄λ‹€.
(ν•Έλ“œμ‰μ΄ν‚Ή 및 HTTP TCP에 λŒ€ν•œ κ°œλ…μ€ 이 κ²Œμ‹œκΈ€μ—μ„œ 닀룬 μ μžˆλ‹€. μ°Έκ³ !)

접속 μš”μ²­μ€ HTTP 둜 ν•œ λ’€, μ›Ήμ†ŒμΌ“ ν”„λ‘œν† μ½œλ‘œ λ³€κ²½λœλ‹€. (WS)

μ›Ήμ†ŒμΌ“ ν”„λ‘œν† μ½œλ‘œ λ³€κ²½λ˜κΈ° μœ„ν•œ HTTP ν—€λ”λŠ” μ•„λž˜μ²˜λŸΌ κ΅¬μ„±λ˜μ–΄ μžˆλ‹€.
(ws://localhost:8080/chat으둜 μ ‘μ†ν•˜λ €κ³  ν•œλ‹€κ³  κ°€μ •ν•œλ‹€.)

πŸ€“ μš”μ²­(Request) 헀더

GET /chat HTTP/1.1
Host: localhost:8080
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://localhost:9000

GET /chat HTTP/1.1
μ›Ήμ†ŒμΌ“μ˜ 톡신 μš”μ²­μ—μ„œ,
HTTP 버전은 1.1 μ΄μƒμ΄μ–΄μ•Όν•˜κ³  GET λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•΄μ•Όν–”λ‹€.

 

Upgrade
ν”„λ‘œν† μ½œμ„ μ „ν™˜ν•˜κΈ° μœ„ν•΄ μ‚¬μš©ν•˜λŠ” 헀더.
μ›Ήμ†ŒμΌ“ μš”μ²­μ‹œμ—λŠ” λ°˜μŠ€μ— websocket μ΄λΌλŠ” 값을 κ°€μ§€λ©°,
이 값이 μ—†κ±°λ‚˜ λ‹€λ₯Έ 값이면 cross-protocol attack 이라고 κ°„μ£Όν•˜μ—¬ μ›Ή μ†ŒμΌ“ 접속을 μ€‘μ§€μ‹œν‚¨λ‹€.

 

Connection
ν˜„μž¬μ˜ 전솑이 μ™„λ£Œλœ ν›„ λ„€νŠΈμ›Œν¬ 접속을 μœ μ§€ν•  것인가에 λŒ€ν•œ 정보.
μ›Ή μ†ŒμΌ“ μš”μ²­ μ‹œμ—λŠ” λ°˜λ“œμ‹œ Upgrade λΌλŠ” 값을 κ°€μ§„λ‹€.
Upgrade 와 λ§ˆμ°¬κ°€μ§€λ‘œ 이 값이 μ—†κ±°λ‚˜ λ‹€λ₯Έ 값이면 μ›Ήμ†ŒμΌ“ 접속을 μ€‘μ§€μ‹œν‚¨λ‹€.

 

Sec-WebSocket-Key
μœ νš¨ν•œ μš”μ²­μΈμ§€ ν™•μΈν•˜κΈ° μœ„ν•΄ μ‚¬μš©ν•˜λŠ” ν‚€ κ°’

 

Sec-WebSocket-Protocol
μ‚¬μš©ν•˜κ³ μž ν•˜λŠ” ν•˜λ‚˜ μ΄μƒμ˜ μ›Ή μ†ŒμΌ“ ν”„λ‘œν† μ½œ μ§€μ •.
ν•„μš”ν•œ κ²½μš°μ—λ§Œ μ‚¬μš©

 

Sec-WebSocket-Version
ν΄λΌμ΄μ–ΈνŠΈκ°€ μ‚¬μš©ν•˜κ³ μž ν•˜λŠ” μ›Ήμ†ŒμΌ“ ν”„λ‘œν† μ½œ 버전.
ν˜„μž¬ μ΅œμ‹  버전 13

 

Origin
CORS μ •μ±…μœΌλ‘œ λ§Œλ“€μ–΄μ§„ 헀더.
Cross-Site Websocket Hijackingκ³Ό 같은 곡격을 ν”Όν•˜κΈ° μœ„ν•¨.

πŸ€“ 응닡(Response) 헀더

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

HTTP/1.1 101 Switching Protocols
101은 HTTPμ—μ„œ WS둜 ν”„λ‘œν† μ½œ μ „ν™˜μ΄ 승인 λ˜μ—ˆλ‹€λŠ” μ‘λ‹΅μ½”λ“œμ΄λ‹€.

 

Sec-WebSocket-Accept
μš”μ²­ ν—€λ”μ˜ Sec-WebSocket-Key에 μœ λ‹ˆν¬ 아이디λ₯Ό λ”ν•΄μ„œ SHA-1둜 ν•΄μ‹±ν•œ ν›„ base64둜 μΈμ½”λ”©ν•œ 결과이닀.
μ›Ή μ†ŒμΌ“ 연결이 κ°œμ‹œλ˜μ—ˆμŒμ„ μ•Œλ¦°λ‹€.

🀝 Data Transfer

Opening HandShakeμ—μ„œ 승인이 λ‚˜κ³ λ‚˜λ©΄,
μ›Ή μ†ŒμΌ“ ν”„λ‘œν† μ½œλ‘œ λ…Έλž€μƒ‰ λ°•μŠ€ 뢀뢄인 Data transfer 이 μ§„ν–‰λœλ‹€.
μ—¬κΈ°μ„œ λ°μ΄ν„°λŠ” λ©”μ‹œμ§€λΌλŠ” λ‹¨μœ„λ‘œ μ „λ‹¬λœλ‹€.

 

λ©”μ‹œμ§€
μ—¬λŸ¬ ν”„λ ˆμž„(frame)이 λͺ¨μ—¬μ„œ κ΅¬μ„±λ˜λŠ” ν•˜λ‚˜μ˜ 논리적인 λ©”μ‹œμ§€ λ‹¨μœ„

 

ν”„λ ˆμž„
ν†΅μ‹ μ—μ„œ κ°€μž₯ μž‘μ€ λ‹¨μœ„μ˜ 데이터.
응? κ°€μž₯ μž‘μ€ λ‹¨μœ„μ˜ λ°μ΄ν„°λŠ” νŒ¨ν‚·μ΄λΌκ³  λΆ€λ₯΄μ§€ μ•Šλ‚˜? 라고 생각할 수 μžˆλ‹€.
λ¬Όλ‘  λ§žλŠ” 말이닀.
νŒ¨ν‚·μ€ μ „ λ„€νŠΈμ›Œν¬ 톡신 κ³Όμ •μ—μ„œ κ°€μž₯ μž‘μ€ λ‹¨μœ„μ˜ 데이터λ₯Ό λœ»ν•˜κ³ ,
ν”„λ ˆμž„μ€ 데이터 링크계측(이더넷)μ—μ„œ μ£Όκ³  λ°›λŠ” κ°€μž₯ μž‘μ€ λ‹¨μœ„λ₯Ό μ˜λ―Έν•œλ‹€.
μž‘μ€ 헀더 + payload 둜 κ΅¬μ„±λ˜μ–΄ μžˆλ‹€.

⚑ Socket.io

μ›Ήμ†ŒμΌ“μ€ HTML5의 기술이기 λ•Œλ¬Έμ— 였래된 λ²„μ „μ˜ μ›Ή λΈŒλΌμš°μ €λŠ” μ›Ή μ†ŒμΌ“μ„ μ§€μ›ν•˜μ§€ μ•ŠλŠ”λ‹€.
이λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ λ‚˜μ˜¨ 기술 쀑 ν•˜λ‚˜κ°€ Socket.io이닀.

 

μ–‘λ°©ν–₯ 톡신을 ν•˜κΈ° μœ„ν•΄ μ›Ή μ†ŒμΌ“ κΈ°μˆ μ„ ν™œμš©ν•˜λŠ” Node.js 라이브러리.
μ›Ήμ†ŒμΌ“, 폴링, 슀트리밍 λ“± λ‹€μ–‘ν•œ 방법을 ν•˜λ‚˜μ˜ API둜 μΆ”μƒν™”ν•œ 것이닀.
μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό μ΄μš©ν•˜μ—¬ λΈŒλΌμš°μ € μ’…λ₯˜μ— 상관 없이 μ‹€μ‹œκ°„ 웹을 κ΅¬ν˜„ν•  수 μžˆλ‹€.

 


이번 ν¬μŠ€νŒ…μ—μ„  μ›Ήμ†ŒμΌ“μ˜ κ°œλ…μ— λŒ€ν•΄ μ•Œμ•„λ³΄μ•˜λ‹€.

λŒ“κΈ€, ν•˜νŠΈ, ν”Όλ“œλ°±μ€ μ–Έμ œλ‚˜ ν™˜μ˜μž…λ‹ˆλ‹€πŸ‘Ό

 

 

μ°Έμ‘° λ¬Έμ„œ