본문으로 건너뛰기
yceffort
PostsSeriesTagsAbout🧪 Research
EN

Tweaks

theme
accent palette
film grain
minimal mode
BACK TO INDEX
◆ ESSAY
--min
--year
KOoriginal

mailMail icongithubtwitter
yceffort
•
© 2026
•
https://yceffort.kr
BACK TO INDEX
◆ ESSAY

Socket.IO 공부하기 (1)

avatar
yceffort
2020-03-22 · 4분
4min
2020year
KOoriginal
nodejswebsocket

WebSocket

웹은 전형적으로 HTTP 요청에 대한 HTTP 응답을 받고, 이에 따라 브라우저 화면을 새로 만드는 방식이다. 따라서 데이터 통신은 요청과 응답이 한 쌍으로 묶여왔다. 그러나 웹 페이지가 보다 쉽게 상호작용을 하려면, 브라우저와 웹 사이에 이러한 요청 - 응답 방식이 아닌 더 자유로운 양방향 메시지 송수신 기술이 필요하다. 이러한 요구를 충족하기 위해 HTML5에서 표준안의 일부로 WebSocket이 등장하였다.

  • 문서보기: https://html.spec.whatwg.org/multipage/web-sockets.html
  • Caniuse: https://caniuse.com/#feat=websockets

Socket.io

https://github.com/socketio/socket.io

Socket.io는 WebSocket이 나올 당시 (2011년 쯤?) 모든 브라우저가 지원하지는 않았으므로, 대다수의 브라우저에 WebSocket 기능을 사용할 수 있도록 구현한 라이브러리다. Github의 used by 로 봐서는 요즘에도 많이 쓰고 있는 것 같다.

Express를 활용한 기본적인 예제

1. 기본설정

먼저 npm에서 socket.io를 설치한다.

var app = require('express')()
var http = require('http').createServer(app)
var io = require('socket.io')(http)

// index.html을 서빙한다
app.get('/', function (req, res) {
  res.sendFile(__dirname + '/index.html')
})

// 'connection' 이라는 이벤트를 감지한다.
io.on('connection', function (socket) {
  console.log('a user connected')
})

// http를 3000포트에서 실행한다.
http.listen(3000, function () {
  console.log('listening on *:3000')
})

이제 localhost:3000 으로 접속하면 아래와 같은 로그를 확인할 수 있다.

listening on *:3000
a user connected

연결 외에 연결 종료를 감지하면 아래와 같이 코드를 추가한다.

io.on('connection', function (socket) {
  console.log('a user connected')
  socket.on('disconnect', function () {
    console.log('user disconnected')
  })
})

다시 실행하고, 페이지를 닫으면 이제 아래와 같이 로그가 찍힌다.

listening on *:3000
a user connected
user disconnected
a user connected
user disconnected

2. 이벤트 보내기

이제 클라이언트에서 이벤트를 보내보자. 기본적으로 보낼 수 있는 객체는 JSON형태이며, binary data도 가능하다.

<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script>
  $(function () {
    var socket = io()
    $('form').submit(function (e) {
      e.preventDefault() // prevents page reloading
      socket.emit('chat message', $('#m').val())
      $('#m').val('')
      return false
    })
  })
</script>
io.on('connection', function (socket) {
  socket.on('chat message', function (msg) {
    console.log('message: ' + msg)
  })

  socket.on('disconnect', function () {
    console.log('user disconnected')
  })
})
> node index.js

listening on *:3000
message: 와
message: 이렇게 메시지가 가는구나
message: 신기하네

3. 브로드캐스팅

브로드 캐스팅은 서버에서 현재 connection으로 접속한 모든 유저에게 이벤트를 보내는 것이다. io.emit을 활용하면 된다.

io.on('connection', function (socket) {
  socket.on('chat message', function (msg) {
    // chat message를 보낸 사용자를 제외한 모든 사용자에게 emit
    // socket.broadcast.emit(msg)
    // 그냥 모든 사용자에게 emit
    io.emit('chat message', msg)
  })

  socket.on('disconnect', function () {
    console.log('user disconnected')
  })
})

이제 클라이언트 사이드에서 'chat message' 를 감지한다.

<script>
  $(function () {
    var socket = io()
    $('form').submit(function (e) {
      e.preventDefault() // prevents page reloading
      socket.emit('chat message', $('#m').val())
      $('#m').val('')
      return false
    })
    socket.on('chat message', function (msg) {
      $('#messages').append($('<li>').text(msg))
    })
  })
</script>

기본적인 채팅기능은 만들었지만, 실제 활용하기엔 조금 거리가 있다. 소켓서버와 채팅서버가 같이있고, 채팅방도 단 하나 뿐이다. 다음 예제에서는 koa와 함께 소켓서버를 따로 구축하고, 채팅 (frontend)과 분리해서 여러개의 채팅방을 만드는 예제를 해보려고 한다.

관련 글

  • ◆ OG 스크래핑 서버 설계 노트
    #nodejs#security#ssrf

    OG 스크래핑 서버를 Node.js로 짓는다면 (2): SSRF는 어떻게 뚫리는가

    사용자가 준 URL을 서버가 대신 여는 기능은 SSRF의 교과서적 조건을 명세로 갖고 있다. 화이트리스트를 뚫는 우회 여섯 가지를 먼저 보고, 그것을 막는 방어 원리 다섯 개를 Node에서 실제로 돌려본 기록. 손으로 IPv4-mapped를 벗기면 16진 표기에서 뚫리고, undici의 lookup 훅은 호스트가 IP 리터럴이면 아예 호출되지 않으며, URL.hostname은 IPv6 리터럴의 대괄호를 남긴다. OG 스크래핑 서버 설계 노트 2부작의 마지막 편이다.

    2026-08-22·39분
  • ◆ OG 스크래핑 서버 설계 노트
    #nodejs#web#scraping

    OG 스크래핑 서버를 Node.js로 짓는다면 (1): 런타임 선택부터 에러율과 지연까지

    링크 미리보기 서버의 "에러율 10%"는 성질이 다른 다섯 종류의 실패가 뭉친 숫자다. 이 워크로드가 왜 I/O 바운드에 저 TPS인지, 런타임 선택이 실제로 갈리는 네 지점은 어디인지 따져본 뒤, User-Agent와 인코딩으로 에러율을 낮추는 일로 넘어간다. Node 내장 TextDecoder는 CP949 확장 문자를 에러 없이 다른 글자로 바꾸고, 스크랩해 온 og:title은 API 응답이 아니라 사용자 입력이다. 캐시 스탬피드와 negative caching, 그리고 "P95 1초 미만"을 캐시 히트율에서 역산해 검증하는 200만 건 시뮬레이션까지 담았다. OG 스크래핑 서버 설계 노트 2부작의 첫 편이다.

    2026-08-22·53분
  • ◆ 프론트엔드 개발자가 알아야 할 쿠버네티스
    #kubernetes#autoscaling#nextjs

    오토스케일링은 자동이지만 즉시가 아니다: HPA의 시간을 구간별로 실측한 기록

    트래픽을 12배로 올리고 새 파드가 첫 요청을 받기까지 31.5초. 그 31.5초의 내역서를 스톱워치로 뽑았다. 감지 창이 지배하는 구조, 배포 직후 5분 창에서 오토스케일러가 눈을 잃는 조건, 안정화 창의 계단, 메모리 HPA가 Node에서 불발되는 이유, KEDA의 선제 확장까지. 프론트엔드 개발자를 위한 쿠버네티스 시리즈의 다섯 번째 편이다.

    2026-08-10·39분
  • ◆ 프론트엔드 개발자가 알아야 할 쿠버네티스
    #kubernetes#nextjs#nodejs

    파드는 어떻게 종료되는가: 배포 중 에러의 원인과 해결을 실측한 기록

    코드를 한 줄도 바꾸지 않은 배포에서도 에러는 샌다. 롤링 배포 중 새는 실패를 유형과 시각까지 태깅해 원인 네 가지를 부검하고, 처방을 한 층씩 얹어 0으로 만들기까지의 실측 기록이다. Next.js의 종료 코드 원문과 인질 드레인, CrashLoopBackOff의 실제 시간표까지. 프론트엔드 개발자를 위한 쿠버네티스 시리즈의 네 번째 편이다.

    2026-08-08·36분

새 글을 놓치고 싶지 않으시다면 RSS로 구독해 주세요.

RSS 구독 →

yceffort — 프론트엔드 엔지니어입니다. 발표·기술 자문·기고 문의는 이곳에서 받고 있습니다.

← Back to the blogIssue on GitHub →