Socket.io adalah sebuah pustaka JavaScript yang memungkinkan komunikasi real-time, dua arah, dan berbasis event antara klien dan server. Pustaka ini menjadi pilihan utama untuk pengembangan aplikasi chatting berbasis web dan berbagai aplikasi web interaktif lainnya.
Berikut adalah beberapa keuntungan menggunakan Socket.IO:
- Komunikasi Read-Time: Memungkinkan pertukaran data instan antara klien dan server.
- Kompabilitas yang Baik: Dapat bekerja di berbagai browser dan platform dengan dukungan fallback.
- Komunikasi Berbasis Event: Memfasilitasi pengiriman dan penerimaan event antara klien dan server.
- Skalabilitas: Dapat menangani banyak koneksi secara bersamaan, cocok untuk aplikasi besar.
Dengan demikian, Socket.io memastikan bahwa aplikasi Anda tetap responsif dan dapat diakses oleh berbagai pengguna, terlepas dari keterbatasan teknologi mereka.
Project initialization
Pastikan NodeJS telah terinstall di server.
$ node -v
v20.11.0
Selanjutnya install package express@4
npm install express@4
Lalu test dengan membuat index.js
seperti berikut.
const express = require('express');
const { createServer } = require('node:http');
const app = express();
const server = createServer(app);
app.get('/', (req, res) => {
res.send('<h1>Hello world</h1>');
});
server.listen(3000, () => {
console.log('server running at http://localhost:3000');
});
Jalankan node index.js.
$ node index.js
server running at http://localhost:3000
Akses http://localhost:3000
dengan browser.
Serving HTML
Edit index.js seperti berikut.
const express = require('express');
const { createServer } = require('node:http');
const { join } = require('node:path');
const app = express();
const server = createServer(app);
app.get('/', (req, res) => {
res.sendFile(join(__dirname, 'index.html'));
});
server.listen(3000, () => {
console.log('server running at http://localhost:3000');
});
Selanjutnya buat file index.html
lalu tambahkan content berikut.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Socket.IO chat</title>
<style>
body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
#form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); }
#input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; }
#input:focus { outline: none; }
#form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages > li { padding: 0.5rem 1rem; }
#messages > li:nth-child(odd) { background: #efefef; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form id="form" action="">
<input id="input" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
Jalankan kembali node index.js
lalu akses http://localhost:3000
Integrating Socket.IO
Socket.IO terdiri dari 2 bagian:
socket.io
: Untuk berintegrasi dengan server HTTP Node.js.socket.io-client
: Library klien yang dimuat di sisi browser.
Selama pengembangan, socket.io
dapat melayani klien secara otomatis sehingga kita hanya perlu menginstall satu modul.
npm install socket.io
Kemudian edit index.js
dengan menambahkan baris berikut.
const express = require('express');
const { createServer } = require('node:http');
const { join } = require('node:path');
const { Server } = require('socket.io');
const app = express();
const server = createServer(app);
const io = new Server(server);
app.get('/', (req, res) => {
res.sendFile(join(__dirname, 'index.html'));
});
io.on('connection', (socket) => {
console.log('a user connected');
});
server.listen(3000, () => {
console.log('server running at http://localhost:3000');
});
Edit index.html
dan tambahkan baris berikut sebelum </body>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
</script>
Anda bisa menemukan versi lokal dari socket.io.js
pada direktori ./node_modules/socket.io/client-dist
. Selain itu juga terdapat CDN sebagai pengganti file lokal.
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
Jalankan kembali node index.js
lalu akses `http://localhost:3000.
$ node index.js
server running at http://localhost:3000
a user connected
Sampai disini Anda telah berhasil mengintegrasikan socket.io sehingga dapat terhubung saat diakses dengan browser.
Tambahkan disconnect
event untuk mengetahui sambungan socket telah terputus.
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
Emitting events
Bagian ini kita akan membuat socket.io dapat mengirim dan menerima event apapun yang Anda inginkan.
Edit bagian <script>
pada index.html
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
const form = document.getElementById('form');
const input = document.getElementById('input');
form.addEventListener('submit', (e) => {
e.preventDefault();
if (input.value) {
socket.emit('chat message', input.value);
input.value = '';
}
});
</script>
Kemudian tambahkan baris berikut pada index.js
untuk menampilkan chat message
event.
io.on('connection', (socket) => {
socket.on('chat message', (msg) => {
console.log('message: ' + msg);
});
});
Jalankan ulang node index.js
dan kirimkan pesan dari browser.
$ node index.js
server running at http://localhost:3000
a user connected
message: test pesan
Broadcasting
Jika sebelumnya pesan tampil di konsol terminal, selanjutnya kita akan membuat pesan tersebut tampil juga di browser menggunakan metode io.emit()
Edit index.js
lalu tambahkan baris berikut.
io.on('connection', (socket) => {
socket.on('chat message', (msg) => {
io.emit('chat message', msg);
});
});
Edit bagian <script>
pada index.html
seperti berikut.
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
const form = document.getElementById('form');
const input = document.getElementById('input');
const messages = document.getElementById('messages');
form.addEventListener('submit', (e) => {
e.preventDefault();
if (input.value) {
socket.emit('chat message', input.value);
input.value = '';
}
});
socket.on('chat message', (msg) => {
const item = document.createElement('li');
item.textContent = msg;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
});
</script>
Jalankan ulang node index.js
dan test kirim pesan dari browser.
Server delivery
Bagian ini kita akan mengatur agar setiap pesan tersimpan di dalam DB menggunakan modul SQLite.
Install modul SQLite
npm install sqlite sqlite3
Kemudian edit index.js seperti berikut.
const express = require('express');
const { createServer } = require('node:http');
const { join } = require('node:path');
const { Server } = require('socket.io');
const sqlite3 = require('sqlite3');
const { open } = require('sqlite');
async function main() {
// open the database file
const db = await open({
filename: 'chat.db',
driver: sqlite3.Database
});
// create our 'messages' table (you can ignore the 'client_offset' column for now)
await db.exec(`
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
client_offset TEXT UNIQUE,
content TEXT
);
`);
const app = express();
const server = createServer(app);
const io = new Server(server, {
connectionStateRecovery: {}
});
app.get('/', (req, res) => {
res.sendFile(join(__dirname, 'index.html'));
});
io.on('connection', (socket) => {
socket.on('chat message', async (msg) => {
let result;
try {
// store the message in the database
result = await db.run('INSERT INTO messages (content) VALUES (?)', msg);
} catch (e) {
// TODO handle the failure
return;
}
// include the offset with the message
io.emit('chat message', msg, result.lastID);
});
});
server.listen(3000, () => {
console.log('server running at http://localhost:3000');
});
}
main();
Selanjutnya tambahkan serverOffset
untuk menyesuaikan atau menyinkronkan waktu antara server dan client.
index.html
<script>
const socket = io({
auth: {
serverOffset: 0
}
});
const form = document.getElementById('form');
const input = document.getElementById('input');
const messages = document.getElementById('messages');
form.addEventListener('submit', (e) => {
e.preventDefault();
if (input.value) {
socket.emit('chat message', input.value);
input.value = '';
}
});
socket.on('chat message', (msg, serverOffset) => {
const item = document.createElement('li');
item.textContent = msg;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
socket.auth.serverOffset = serverOffset;
});
</script>
index.js
// [...]
io.on('connection', async (socket) => {
socket.on('chat message', async (msg) => {
let result;
try {
result = await db.run('INSERT INTO messages (content) VALUES (?)', msg);
} catch (e) {
// TODO handle the failure
return;
}
io.emit('chat message', msg, result.lastID);
});
if (!socket.recovered) {
// if the connection state recovery was not successful
try {
await db.each('SELECT id, content FROM messages WHERE id > ?',
[socket.handshake.auth.serverOffset || 0],
(_err, row) => {
socket.emit('chat message', row.content, row.id);
}
)
} catch (e) {
// something went wrong
}
}
});
// [...]
Jalankan ulang node index.js
dan test melalui browser.
Referensi: