λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

Web

[Web] Socket, WebSocket (μ†ŒμΌ“κ³Ό μ›Ήμ†ŒμΌ“)

ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜λ©΄μ„œ μ†ŒμΌ“μ„ 정말 많이 μ‚¬μš©ν•˜κ²Œ λ˜μ—ˆμ—ˆλ‹€. μ‹œκ°„μ΄ κ½€ μ§€λ‚¬μ§€λ§Œ λ‹€μ‹œ ν•œλ²ˆ ν•™μŠ΅ν•΄λ³΄λ©΄μ„œ 볡기도 ν•˜κ³  λ‚˜λ¦„λŒ€λ‘œ 정리도 해보렀고 포슀트λ₯Ό μž‘μ„±ν•˜κΈ° μ‹œμž‘ν–ˆλ‹€!

🌏 Socket

  • ν”„λ‘œκ·Έλž¨μ΄ λ„€νŠΈμ›Œν¬μ—μ„œ λ°μ΄ν„°λ₯Ό μ£Όκ³ λ°›μ„ μˆ˜ μžˆλ„둝 λ„€νŠΈμ›Œν¬ ν™˜κ²½μ— μ—°κ²°ν•  μˆ˜ μžˆκ²Œ λ§Œλ“€μ–΄μ§„ μ—°κ²°λΆ€
  • 데이터λ₯Ό μ£Όκ³  받을 수 μžˆλŠ” ꡬ쑰체둜 μ†ŒμΌ“μ„ 톡해 데이터 ν†΅λ‘œκ°€ λ§Œλ“€μ–΄μ§„λ‹€.
  • μ„œλ²„ μ†ŒμΌ“, ν΄λΌμ΄μ–ΈνŠΈ μ†ŒμΌ“μœΌλ‘œ κ΅¬λΆ„λœλ‹€. (μš”μ²­μ„ ν•˜λŠ” μͺ½μ΄ ν΄λΌμ΄μ–ΈνŠΈ, λ°›λŠ” μͺ½μ΄ μ„œλ²„)
  • TCP/IP, UDP/IP μœ ν˜•μ΄ μ‘΄μž¬ν•˜λ‚˜ 일반적으둜 TCP/IP ν”„λ‘œν† μ½œμ„ μ΄μš©ν•¨.
  • μ†ŒμΌ“μ€ ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„κ°€ 데이터 νŒ¨ν‚·μ„ κ΅ν™˜ν•  수 μžˆλ„λ‘ ν•˜λŠ” IP μ£Όμ†Œμ™€ 포트 번호라고 ν•˜λŠ” ν†΅μ‹ μš© 끝점(End-Point)을 λ§Œλ“€μ–΄ μž‘λ™

πŸ“’ λ™μž‘방식

(좜처 - https://on1ystar.github.io/socket%20programming/2021/03/16/socket-1/)

βœ“ Server

  1. socket(): μ†ŒμΌ“ 생성(TCPλŠ” stream)
    • μƒˆλ‘œμš΄ client의 μš”μ²­μ„ λŒ€κΈ°ν•˜κΈ° μœ„ν•¨
  2. bind(): μ‚¬μš©ν•  IP address와 Port number 등둝
    • 포트 λ²ˆν˜Έκ°€ λ‹€λ₯Έ μ†ŒμΌ“μ˜ 포트 λ²ˆν˜Έμ™€ μ€‘λ³΅λ˜μ§€λŠ” μ•Šμ„κΉŒ?
    • μš΄μ˜μ²΄μ œμ—μ„œλŠ” μ†ŒμΌ“λ“€μ΄ μ€‘λ³΅λœ 포트 번호λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šλ„λ‘, λ‚΄λΆ€μ μœΌλ‘œ 포트 λ²ˆν˜Έμ™€ μ†ŒμΌ“ μ—°κ²° 정보λ₯Ό κ΄€λ¦¬ν•œλ‹€.
  3. listen(): μ—°κ²° λ˜μ§€ μ•Šμ€ μ†ŒμΌ“μ„ μš”μ²­ μˆ˜μ‹  λŒ€κΈ° λͺ¨λ“œλ‘œ μ „ν™˜(Block μƒνƒœ)
  4. accept(): client의 μš”μ²­dmf 수락 → 톡신을 μœ„ν•œ μƒˆλ‘œμš΄ μ†ŒμΌ“ 생성(μ‹€μ§ˆμ μΈ μ†ŒμΌ“ μ—°κ²°)

βœ“ Client

  1. socket(): λ§ˆμ°¬κ°€μ§€λ‘œ μ†ŒμΌ“ 생성(TCPλŠ” stream)
  2. connect(): Clientμ—μ„œ Server와 μ—°κ²°ν•˜κΈ° μœ„ν•΄ μ†ŒμΌ“κ³Ό λͺ©μ μ§€ IP address, Port number 지정 (Block μƒνƒœ)

βœ“ Server-Client

  • send()recv(): ClientλŠ” μ²˜μŒμ— μƒμ„±ν•œ μ†ŒμΌ“μœΌλ‘œ, ServerλŠ” μƒˆλ‘œ λ°˜ν™˜(생성)된 μ†ŒμΌ“μœΌλ‘œ client와 server간에 데이터 μ†‘μˆ˜μ‹ 
  • close(): μ†ŒμΌ“μ„ λ‹«μŒ

 

🌏 WebSocket

μ†ŒμΌ“μ€ 두 컴퓨터 κ°„μ˜ 톡신을 μ„€μ •ν•˜κΈ° μœ„ν•œ κΈ°λ³Έ λ©”μ»€λ‹ˆμ¦˜μ„ μ œκ³΅ν•˜λŠ” 반면 μ›Ή μ†ŒμΌ“μ€ μ†ŒμΌ“ μœ„μ— κ΅¬μΆ•λ˜μ–΄ μ›Ή ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„ κ°„μ˜ μ‹€μ‹œκ°„ 전이쀑 톡신을 μœ„ν•œ μƒμœ„ μˆ˜μ€€ ν”„λ‘œν† μ½œμ„ μ œκ³΅ν•˜λŠ” 것이 차이점이닀. (μ›Ή μ†ŒμΌ“μ€ HTTP λ ˆμ΄μ–΄μ—μ„œ λ™μž‘, μ†ŒμΌ“μ€ TCP/IP) 

 

μ›Ήμ†ŒμΌ“μ€ HTTP둜 μ‹€μ‹œκ°„ 톡신을 ν•˜λŠ” 것이 μ–΄λ €μ› κΈ° λ•Œλ¬Έμ— ν•΄κ²°μ±…μœΌλ‘œ λ‚˜μ˜¨ κΈ°μˆ μ΄λ‹€.

HTTP μ‹€μ‹œκ°„ ν†΅μ‹ μ˜ μ–΄λ €μš΄ 이유
1. λΉ„μ—°κ²°μ„±μœΌλ‘œ μΈν•œ 단방ν–₯ 톡신
2. λΉ„μ—°κ²°μ„±μœΌλ‘œ μΈν•œ 맀번 μ—°κ²° λ§Ίκ³  λŠλŠ” κ³Όμ •μ˜ λΉ„μš©
3. request-response 의 ꡬ쑰
4. ν—€λ”μ˜ 비쀑이 λ„ˆλ¬΄ 큼

 

πŸ“’ λ™μž‘λ°©μ‹

λ¨Όμ € μ†ŒμΌ“ 연결을 ν•˜κΈ° μœ„ν•΄ ν•Έλ“œμ‰μ΄ν‚Ήμ΄ ν•„μš”ν•˜λ‹€ μ΄λ•Œ HTTP λ˜λŠ” HTTPS ν”„λ‘œν† μ½œμ„ 톡해 이루어진닀.

ν΄λΌμ΄μ–ΈνŠΈμ˜ μš”μ²­ 헀더

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13

 

  • Method: λ°˜λ“œμ‹œ GET μš”μ²­μœΌλ‘œ 보내야 함.
  • Host: μ›Ήμ†ŒμΌ“ μ„œλ²„μ˜ μ£Όμ†Œ
  • Upgrade: ν˜„μž¬ ν”„λ‘œν† μ½œμ—μ„œ λ‹€λ₯Έ ν”„λ‘œν† μ½œλ‘œ μ—…κ·Έλ ˆμ΄λ“œ, λ³€κ²½ν•˜κΈ° μœ„ν•¨(webSocket ν”„λ‘œν† μ½œλ‘œ λ³€ν™˜)
  • Connection: Upgrade ν•„λ“œκ°€ λͺ…μ‹œλ˜μ–΄μžˆλ‹€λ©΄, Connection ν•„λ“œλ„ λͺ…μ‹œν•΄μ€˜μ•Ό 함.
  • Sec-WebSocket-Key: 길이가 16 λ°”μ΄νŠΈμΈ μž„μ˜μ˜ κ°’μœΌλ‘œ ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„κ°€ 신원을 μΈμ¦ν•˜λŠ”λ° μ‚¬μš©

이외에도 ν΄λΌμ΄μ–ΈνŠΈλŠ” μ—¬λŸ¬ λ©”μ„Έμ§€λ‚˜ μ„œλΈŒν”„λ‘œν† μ½œμ„ μΆ”κ°€ν•΄ 보낼 μˆ˜λ„ μžˆλ‹€. (User-Agent, Referer, Cookie λ“±) μ›ν•˜λŠ” λŒ€λ‘œ μš”μ²­μ— 무엇이든지 μ²¨λΆ€ν•˜μ—¬ 보낼 수 μžˆμ§€λ§Œ μ›Ήμ†ŒμΌ“κ³Ό 관련이 없을 경우 λ¬΄μ‹œν•œλ‹€.

 

μ„œλ²„μ˜ 응닡 헀더

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

 

101 Switching Protocols으둜 응닡이 였면 μ›Ήμ†ŒμΌ“μ΄ μ—°κ²°λ˜μ—ˆλ‹€λŠ” μ˜λ―Έμ΄λ‹€.

ν΄λΌμ΄μ–ΈνŠΈκ°€ 보낸 헀더가 잘λͺ»λœ 값을 κ°€μ§€κ±°λ‚˜ ν˜•μ‹μ΄ 잘λͺ»λœ ν—€λ”μ˜ 경우, μ„œλ²„λŠ” "400 Bad Request (en-US)" 응닡을 보내 μ¦‰μ‹œ μ†ŒμΌ“μ„ μ’…λ£Œμ‹œν‚¨λ‹€.

 

이런 과정을 ν†΅ν•΄μ„œ ν”„λ‘œν† μ½œμ΄ ws, wss(WebSocket)으둜 λ³€ν™˜λ˜λ©΄ frame을 μ‚¬μš©ν•˜μ—¬ 데이터λ₯Ό κ΅ν™˜ν•  수 μžˆλ‹€.

Frame

WebSocket의 데이터 κ΅ν™˜μ—μ„œ μ‚¬μš©λ˜λŠ” κ°€μž₯ μž‘μ€ λ‹¨μœ„μ˜ λ°μ΄ν„°λ‘œ 헀더와 νŽ˜μ΄λ‘œλ“œλ‘œ κ΅¬μ„±λ˜μ–΄ μžˆλ‹€.

Frame Header

ν—€λ”λŠ” 일반적으둜 길이가 2λ°”μ΄νŠΈμ΄μ§€λ§Œ λŒ€μš©λŸ‰ νŽ˜μ΄λ‘œλ“œμ˜ 경우 μ΅œλŒ€ 14λ°”μ΄νŠΈκΉŒμ§€ κ°€λŠ₯ν•˜λ‹€.

 

1. 첫 번째 λ°”μ΄νŠΈμ— ν¬ν•¨λ˜λŠ” 정보

  • FIN: 이것이 λ©”μ‹œμ§€μ˜ λ§ˆμ§€λ§‰ 쑰각인지 μ—¬λΆ€λ₯Ό λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
  • RSV1, RSV2, RSV3: ν™•μž₯에 μ‚¬μš©ν•  μˆ˜ μžˆλŠ” μ˜ˆμ•½λœ λΉ„νŠΈ
  • Opcode: νŽ˜μ΄λ‘œλ“œ μœ ν˜• μ§€μ •(예: ν…μŠ€νŠΈ, λ°”μ΄λ„ˆλ¦¬, ν•‘ λ“±)

2. 두 번째 λ°”μ΄νŠΈ ν¬ν•¨λ˜λŠ” 정보(νŽ˜μ΄λ‘œλ“œμ— 관함)

  • Mask: νŽ˜μ΄λ‘œλ“œ λ§ˆμŠ€ν‚Ή μ—¬λΆ€ ν‘œμ‹œ
  • νŽ˜μ΄λ‘œλ“œ 길이: νŽ˜μ΄λ‘œλ“œμ˜ 길이 지정

Frame Payload

νŽ˜μ΄λ‘œλ“œμ—λŠ” WebSocket 연결을 톡해 μ „μ†‘λ˜λŠ” μ‹€μ œ 데이터가 ν¬ν•¨λœλ‹€. νŽ˜μ΄λ‘œλ“œκ°€ λ§ˆμŠ€ν‚Ήλœ 경우(ν—€λ”μ˜ 마슀크 ν”Œλž˜κ·Έλ‘œ ν‘œμ‹œλ¨) 헀더에도 ν¬ν•¨λœ λ§ˆμŠ€ν‚Ή 킀와 XOR μ²˜λ¦¬λœλ‹€.

 

νŽ˜μ΄λ‘œλ“œμ˜ κΈΈμ΄λŠ” 헀더에 μ§€μ •λœ νŽ˜μ΄λ‘œλ“œ 길이에 따라 κ°€λ³€ 길이일 수 μžˆλ‹€.

λ§Œμ•½ νŽ˜μ΄λ‘œλ“œ 길이가 125λ°”μ΄νŠΈ μ΄ν•˜μ΄λ©΄ ν”„λ ˆμž„μ— 직접 μ €μž₯λ˜μ§€λ§Œ νŽ˜μ΄λ‘œλ“œ 길이가 125λ°”μ΄νŠΈλ³΄λ‹€ 크면 νŽ˜μ΄λ‘œλ“œ 길이 ν•„λ“œλŠ” 126 λ˜λŠ” 127둜 μ„€μ •λ˜κ³  νŽ˜μ΄λ‘œλ“œμ˜ μ‹€μ œ κΈΈμ΄λŠ” 헀더 뒀에 μ˜€λŠ” λ³„λ„μ˜ ν•„λ“œμ— μ €μž₯λœλ‹€.

 

Frame μ’…λ₯˜ 

Continuation Frames  
Text Frames UTF-8둜 μΈμ½”λ”©λœ ν…μŠ€νŠΈ 데이터λ₯Ό μ „μ†‘ν•˜κΈ° μœ„ν•΄ μ‚¬μš©
Binary Frames λ°”μ΄λ„ˆλ¦¬ 데이터λ₯Ό μ „μ†‘ν•˜κΈ° μœ„ν•΄ μ‚¬μš©
Close Frames 연결을 λ‹«μ•„μ•Ό ν•œλ‹€λŠ” μ‹ ν˜Έλ₯Ό λ³΄λ‚΄λŠ” 데 μ‚¬μš©
Ping Frames 연결이 μ—¬μ „νžˆ ν™œμ„± μƒνƒœμΈμ§€ ν…ŒμŠ€νŠΈν•˜λŠ” 데 μ‚¬μš©
Pong Frames Ping ν”„λ ˆμž„μ— μ‘λ‹΅ν•˜κ³  연결이 μ—¬μ „νžˆ ν™œμ„± μƒνƒœμž„μ„ λ‚˜νƒ€λ‚΄λŠ” 데 μ‚¬μš©

 

🌏 nodeμ—μ„œ μ›Ήμ†ŒμΌ“ μ‚¬μš©ν•˜κΈ°

였래된 λΈŒλΌμš°μ €μ˜ 경우 μ§€μ›ν•˜μ§€ μ•ŠλŠ” 경우 μ‘΄μž¬ν•˜κΈ° λ•Œλ¬Έμ— Cross-platform WebSocket API인 Socket.ioλ₯Ό μ‚¬μš©ν•œλ‹€.

on('λ©”μ†Œλ“œλͺ…', μ½œλ°±ν•¨μˆ˜(data){}) μ†ŒμΌ“ μ—°κ²°λœ μƒλŒ€νŽΈ(λΈŒλΌμš°μ € / μ„œλ²„)μ—μ„œ λ©”μ†Œλ“œλͺ…을 λ§€κ°œλ³€μˆ˜λ‘œ κ°–λŠ” emit ν˜ΈμΆœν•˜λ©΄ 이후 μ½œλ°±ν•¨μˆ˜κ°€ λ™μž‘ν•œλ‹€. emit λ©”μ†Œλ“œμ˜ λ§€κ°œλ³€μˆ˜λ₯Ό data둜 받아와 μ μ ˆν•œ λ™μž‘μ„ μˆ˜ν–‰ν•œλ‹€.
on('connection', function(socket)) μ†ŒμΌ“ 연결을 μœ„ν•΄ ν•„μˆ˜μ μœΌλ‘œ μˆ˜ν–‰λ˜μ–΄μ•Ό ν•˜λŠ” ν•¨μˆ˜.jQueryμ—μ„œ $().ready()와 같은 λŠλ‚ŒμœΌλ‘œ μ‚¬μš©ν•˜λ©΄ λœλ‹€.function의 λ§€κ°œλ³€μˆ˜λ‘œ μ†ŒμΌ“ 객체λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.
emit('λ©”μ†Œλ“œλͺ…', data) μ†ŒμΌ“ μ—°κ²°λœ μƒλŒ€νŽΈ(λΈŒλΌμš°μ € / μ„œλ²„)μ—μ„œ λ©”μ†Œλ“œλͺ…을 κ°–λŠ” on ν•¨μˆ˜λ₯Ό 호좜 ν•œλ‹€. μ΄λ•Œ on ν•¨μˆ˜μ— ν•„μš”ν•œ 데이터λ₯Ό data둜 ν•¨κ»˜ μ „μ†‘ν•œλ‹€.
join("곡간λͺ…") '곡간λͺ…'을 ν‚€λ‘œ ν•΄ μ†ŒμΌ“λ“€μ„ 관리할 수 있게 ν•΄μ£ΌλŠ” λ©”μ†Œλ“œ.

 

Client

import { Socket } from 'socket.io-client';

const socket = Socket.connect();

// μ†ŒμΌ“μ΄ 연결이 됨
socket.on('connect', () => console.log('socket connect!'))

// μ„œλ²„λ‘œλΆ€ν„° 받은 데이터 좜λ ₯
socket.on('μ΄λ²€νŠΈμ΄λ¦„', data => console.log(data));

// μ„œλ²„λ‘œ 전솑
socket.emit('μ΄λ²€νŠΈμ΄λ¦„', {데이터});

 

Server

const httpServer = http.createServer(app);
const io = new Server(httpServer);

// μ†ŒμΌ“ 연결됨
io.on('connection', socket => {
	// ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ 데이터λ₯Ό λ°›κ³  좜λ ₯
    socket.on('μ΄λ²€νŠΈμ΄λ¦„', data => console.log(data));

    // λͺ¨λ“  ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ λ©”μ‹œμ§€λ₯Ό 전솑
    socket.broadcast.emit('μ΄λ²€νŠΈμ΄λ¦„', {보낼 데이터});

    // νŠΉμ • ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ 전솑
    socket.to(id).emit('μ΄λ²€νŠΈμ΄λ¦„', {보낼 데이터})
});

 

좔가적인 λ©”μ„œλ“œλ„ 있고 이미 λ“±λ‘λ˜μ–΄ μžˆλŠ” μ΄λ²€νŠΈλ“€λ„ μžˆλŠ”λ° μžμ„Έν•œκ±΄ κ³΅μ‹λ¬Έμ„œμ—μ„œ μ°Έκ³ ν•˜λ©΄ 쒋을 것 κ°™λ‹€!

https://socket.io/docs/v4/

 

Introduction | Socket.IO

What Socket.IO is

socket.io

 

잘λͺ»λœ λ‚΄μš©μ΄ μžˆλ‹€λ©΄ νŽΈν•˜κ²Œ λ§μ”€λΆ€νƒλ“œλ¦½λ‹ˆλ‹€!!!

 

πŸ“š μ°Έκ³ 

https://www.youtube.com/watch?v=MPQHvwPxDUw 

https://poiemaweb.com/nodejs-socketio

 

Node.js(Express)와 Socket.io | PoiemaWeb

WebSocket, Socket.ioλ₯Ό μ‚¬μš©ν•œ μ‹€μ‹œκ°„ μ±„νŒ… μ• ν”Œλ¦¬μΌ€μ΄μ…˜

poiemaweb.com

https://on1ystar.github.io/socket%20programming/2021/03/16/socket-1/

 

μ†ŒμΌ“ ν”„λ‘œκ·Έλž˜λ° - μ†ŒμΌ“μ˜ 의미/νŠΉμ§•/μ’…λ₯˜ · on1ystar

μ†ŒμΌ“ ν”„λ‘œκ·Έλž˜λ° - μ†ŒμΌ“μ˜ 의미/νŠΉμ§•/μ’…λ₯˜ 16 Mar 2021 μ˜λ¬Έμ μ΄λ‚˜ 지적 λ“±μ˜ 관심 및 쑰언을 μœ„ν•œ λŒ“κΈ€μ΄λ‚˜ 메일은 μ–Έμ œλ‚˜ ν™˜μ˜μ΄κ³  κ°μ‚¬ν•©λ‹ˆλ‹€. Socket 논리적인 의미둜 컴퓨터 λ„€νŠΈμ›Œν¬λ₯Ό κ²½μœ ν•˜

on1ystar.github.io

 

'Web' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[Web] CORS  (0) 2023.05.18
[Web] λΈŒλΌμš°μ €μ—μ„œ 도메인을 μž…λ ₯ν•˜λ©΄ μΌμ–΄λ‚˜λŠ” 일  (0) 2023.03.02
[Web] JWT  (0) 2023.02.25
[Web] Webpack  (0) 2023.02.22