Socket.IO Basics — Realtime

Socket.IO Socket.IO adalah library real-time yang wraps WebSocket dengan fitur tambahan: auto-reconnect, rooms, namespaces, fallback ke polling. Library…

Socket.IO adalah library (bagian server dan bagian client) untuk mengirim event bernama bolak-balik, lengkap dengan reconnect otomatis, antrean saat putus, tanda terima, dan room. Dia berjalan di atas protokolnya sendiri, Engine.IO, yang memakai WebSocket (atau HTTP long polling kalau WebSocket gak tersedia) sebagai jalannya. Bayangin beda telepon biasa dan jasa kurir. WebSocket itu telepon: tersambung, tapi semua urusan kamu atur sendiri. Socket.IO itu kurir: paketnya berlabel ("status order"), ada tanda terima, paket yang dititipkan saat jalan ditutup diantar begitu jalan dibuka, dan bisa dikirim ke satu alamat atau satu kompleks sekaligus.

🧪 Tebakan cepat: Tablet Mas Eko menjalankan socket.emit('order:status', { id: 12, status: 'Disetrika' }). Teks apa yang lewat di koneksi WebSocket-nya: JSON {"id":12,"status":"Disetrika"} saja, atau ada yang lain? Jawabannya ada di bagian "Di kabel: paket Engine.IO dan Socket.IO".

Server dan client

Server realtime Bu Rini di port 3000, memakai socket.io 4.8.4 (versi terbaru per Oktober 2026):

import { Server } from 'socket.io'

const io = new Server(3000, { cors: { origin: 'http://localhost:8000' } })

io.on('connection', (socket) => {
  console.log('tersambung', socket.id)
  socket.on('order:status', (data, ack) => {
    // simpan ke database di sini
    socket.broadcast.emit('order:status', data) // ke semua layar lain
    ack({ ok: true })                           // tanda terima ke pengirim
  })
})

Di browser, dengan socket.io-client 4.8.4:

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

const socket = io('http://localhost:3000')

socket.on('connect', () => console.log('tersambung', socket.id))
socket.on('order:status', ({ id, status }) => {
  document.querySelector(`#status-${id}`).textContent = status
})
socket.emit('order:status', { id: 12, status: 'Disetrika' }, (balasan) => {
  console.log(balasan) // { ok: true }
})

Di kabel: paket Engine.IO dan Socket.IO

Ini isi koneksi yang direkam dari socket.io 4.8.4 (protokol Engine.IO versi 4, protokol Socket.IO versi 5):

GET /socket.io/?EIO=4&transport=polling
<- 0{"sid":"...","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":20000,"maxPayload":1000000}
-> 40                                    <- 40{"sid":"..."}
-> 2probe   <- 3probe   -> 5             (pindah ke WebSocket)
-> 42["order:status",{"id":12,"status":"Disetrika"}]
-> 420["order:status",{"id":13,"status":"Siap diambil"}]
<- 430[{"ok":true}]
<- 2   -> 3                              (ping dari server, pong dari client)
Digit Lapisan Artinya
pertama Engine.IO 0 open, 1 close, 2 ping, 3 pong, 4 message, 5 upgrade, 6 noop
kedua (kalau yang pertama 4) Socket.IO 0 CONNECT, 1 DISCONNECT, 2 EVENT, 3 ACK, 4 CONNECT_ERROR, 5 BINARY_EVENT, 6 BINARY_ACK
sesudahnya Socket.IO nomor tanda terima (kalau ada), lalu array JSON [nama event, data...]

Jadi 42["order:status",{...}] artinya: message (4), event (2), isinya nama dan data. Itu jawaban tebakannya: yang lewat bukan JSON polos, tapi paket ber-awalan. Akibatnya Socket.IO bukan WebSocket biasa. new WebSocket('ws://localhost:3000') gak bisa bicara dengan server Socket.IO (dicoba: koneksi ditolak), dan io() gak bisa tersambung ke server WebSocket biasa.

Client mulai lewat HTTP long polling (transport=polling), lalu pindah ke WebSocket lewat 2probe, 3probe, 5. Pilih io(url, { transports: ['websocket'] }) untuk langsung ke WebSocket.

Tanda terima: acknowledgement

Fungsi di argumen terakhir emit adalah tanda terima. Socket.IO memberi paketnya nomor, mulai dari 0 di tiap koneksi (420 = event dengan tanda terima nomor 0), dan server menjawab dengan nomor yang sama (430[{"ok":true}]).

socket.timeout(5000).emit('order:status', { id: 13, status: 'Siap diambil' }, (err, balasan) => {
  if (err) console.log('server gak menjawab dalam 5 detik')
  else console.log(balasan) // { ok: true }
})

const balasan = await socket.emitWithAck('order:status', { id: 14, status: 'Siap diambil' }) // versi Promise, sejak 4.6

Putus koneksi: reconnect dan antrean

Room, sekilas

Server bisa mengelompokkan socket ke dalam room. HP Pak Darto ikut room order:12, jadi kabar "Siap diambil" cuma sampai ke dia:

socket.join('order:12')                                           // di server
io.to('order:12').emit('order:status', { id: 12, status: 'Siap diambil' })

Room cuma ada di server: client gak bisa masuk room sendiri. Detailnya di pelajaran Rooms & Namespaces.

Socket.IO atau WebSocket biasa?

⚠️ Jebakan yang sering ketemu

TL;DR: Socket.IO adalah library di atas WebSocket (lewat protokol Engine.IO) yang menambah event bernama (emit dan on), tanda terima, reconnect otomatis (1 detik berlipat dua sampai 5 detik, diacak ±50%), antrean emit saat putus, fallback ke HTTP long polling, room, dan namespace. Di kabel, tiap paket punya awalan: 0 open, 2 ping, 3 pong, 40 connect, 42[...] event, 420[...] event dengan tanda terima nomor 0, dijawab 430[...]. Karena itu WebSocket biasa dan Socket.IO gak bisa saling sambung. Pakai socket.timeout(ms).emit(...) atau emitWithAck untuk tanda terima dengan batas waktu, dan pasang cors di server untuk origin papan.

Yang akan kamu pelajari