WebSocket
WebSocket provides two-way (full-duplex) communication between the client and the server over a single TCP connection.
WebSocket Basics
WebSocket Connection
<script>
const socket = new WebSocket('ws://localhost:8080');
socket.onopen = function(event) {
console.log('Connection opened');
socket.send('Hello Server!');
};
socket.onmessage = function(event) {
console.log('Message from server:', event.data);
};
socket.onclose = function(event) {
console.log('Connection closed');
};
socket.onerror = function(error) {
console.log('Error:', error);
};
</script>
Sending and Receiving Data
<script>
const socket = new WebSocket('ws://localhost:8080');
// Send a message
function sendMessage(message) {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({
type: 'chat',
content: message
}));
}
}
// Receive a message
socket.onmessage = function(event) {
const data = JSON.parse(event.data);
console.log('Type:', data.type);
console.log('Content:', data.content);
};
</script>
Case Study: Campus Real-time Chat
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Campus Chat</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', sans-serif;
background: #f0f2f5;
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
background: #1e3a5f;
color: white;
padding: 1rem 1.5rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.header h1 {
font-size: 1.3rem;
}
.status {
display: flex;
align-items: center;
gap: 0.5rem;
}
.status-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: #e74c3c;
}
.status-dot.connected {
background: #2ecc71;
}
.chat-container {
flex: 1;
display: flex;
flex-direction: column;
max-width: 800px;
width: 100%;
margin: 0 auto;
padding: 1rem;
}
.messages {
flex: 1;
overflow-y: auto;
padding: 1rem;
background: white;
border-radius: 8px 8px 0 0;
border: 1px solid #ddd;
border-bottom: none;
}
.message {
margin-bottom: 1rem;
display: flex;
flex-direction: column;
}
.message.sent {
align-items: flex-end;
}
.message.received {
align-items: flex-start;
}
.message .bubble {
max-width: 70%;
padding: 0.8rem 1rem;
border-radius: 12px;
word-wrap: break-word;
}
.message.sent .bubble {
background: #3498db;
color: white;
border-bottom-right-radius: 4px;
}
.message.received .bubble {
background: #e9ecef;
color: #333;
border-bottom-left-radius: 4px;
}
.message .sender {
font-size: 0.75rem;
color: #666;
margin-bottom: 0.25rem;
}
.message .time {
font-size: 0.7rem;
color: #999;
margin-top: 0.25rem;
}
.input-area {
display: flex;
gap: 0.5rem;
padding: 1rem;
background: white;
border: 1px solid #ddd;
border-radius: 0 0 8px 8px;
}
.input-area input {
flex: 1;
padding: 0.8rem;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1rem;
}
.input-area input:focus {
outline: none;
border-color: #3498db;
}
.input-area button {
padding: 0.8rem 1.5rem;
background: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.input-area button:hover {
background: #2980b9;
}
.input-area button:disabled {
background: #bdc3c7;
cursor: not-allowed;
}
.users-list {
padding: 1rem;
background: #f8f9fa;
border-bottom: 1px solid #ddd;
font-size: 0.9rem;
color: #666;
}
.users-list strong {
color: #333;
}
</style>
</head>
<body>
<div class="header">
<h1>Campus Chat</h1>
<div class="status">
<div class="status-dot" id="statusDot"></div>
<span id="statusText">Terputus</span>
</div>
</div>
<div class="chat-container">
<div class="users-list" id="usersList">
<strong>Online users:</strong> Loading...
</div>
<div class="messages" id="messages">
<div class="message system" style="text-align: center; color: #999; font-size: 0.85rem;">
Welcome to Campus Chat!
</div>
</div>
<div class="input-area">
<input type="text" id="messageInput" placeholder="Type a message..." disabled>
<button id="sendBtn" onclick="sendMessage()" disabled>Send</button>
</div>
</div>
<script>
let socket = null;
let username = '';
// Prompt username
username = prompt('Enter your name:') || 'Anonymous';
// WebSocket connection (simulation)
function connect() {
updateStatus('connecting');
// Connection simulation (for a demo without a server)
setTimeout(() => {
updateStatus('connected');
document.getElementById('messageInput').disabled = false;
document.getElementById('sendBtn').disabled = false;
// Simulate online users
updateUsersList(['Anda', 'John', 'Sarah', 'Rahmat']);
// Simulate incoming messages
setTimeout(() => {
addMessage('John', 'Hello everyone!', 'received');
}, 2000);
setTimeout(() => {
addMessage('Sarah', 'Anything you'd like to ask?', 'received');
}, 5000);
}, 1000);
// Real code (uncomment if you have a WebSocket server):
/*
socket = new WebSocket('ws://localhost:8080');
socket.onopen = function() {
updateStatus('connected');
document.getElementById('messageInput').disabled = false;
document.getElementById('sendBtn').disabled = false;
// Send join message
socket.send(JSON.stringify({
type: 'join',
username: username
}));
};
socket.onmessage = function(event) {
const data = JSON.parse(event.data);
switch(data.type) {
case 'chat':
addMessage(data.sender, data.content,
data.sender === username ? 'sent' : 'received');
break;
case 'users':
updateUsersList(data.users);
break;
case 'system':
addSystemMessage(data.content);
break;
}
};
socket.onclose = function() {
updateStatus('disconnected');
};
socket.onerror = function() {
updateStatus('error');
};
*/
}
function sendMessage() {
const input = document.getElementById('messageInput');
const message = input.value.trim();
if (message) {
addMessage(username, message, 'sent');
// Send to server (simulation)
console.log('Mengirim:', message);
// Real code:
/*
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({
type: 'chat',
content: message
}));
}
*/
input.value = '';
}
}
function addMessage(sender, content, type) {
const messages = document.getElementById('messages');
const time = new Date().toLocaleTimeString('id-ID', {
hour: '2-digit',
minute: '2-digit'
});
const messageDiv = document.createElement('div');
messageDiv.className = `message ${type}`;
messageDiv.innerHTML = `
${type === 'received' ? `<span class="sender">${sender}</span>` : ''}
<div class="bubble">${content}</div>
<span class="time">${time}</span>
`;
messages.appendChild(messageDiv);
messages.scrollTop = messages.scrollHeight;
}
function addSystemMessage(content) {
const messages = document.getElementById('messages');
const messageDiv = document.createElement('div');
messageDiv.className = 'message system';
messageDiv.style.textAlign = 'center';
messageDiv.style.color = '#999';
messageDiv.style.fontSize = '0.85rem';
messageDiv.textContent = content;
messages.appendChild(messageDiv);
messages.scrollTop = messages.scrollHeight;
}
function updateStatus(status) {
const dot = document.getElementById('statusDot');
const text = document.getElementById('statusText');
dot.className = 'status-dot';
switch(status) {
case 'connected':
dot.classList.add('connected');
text.textContent = 'Terhubung';
break;
case 'connecting':
text.textContent = 'Menghubungkan...';
break;
case 'disconnected':
text.textContent = 'Terputus';
break;
case 'error':
text.textContent = 'Error';
break;
}
}
function updateUsersList(users) {
const list = document.getElementById('usersList');
list.innerHTML = `<strong>Online users (${users.length}):</strong> ${users.join(', ')}`;
}
// Handle enter key
document.getElementById('messageInput').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});
// Start connection
connect();
</script>
</body>
</html>
Everyday Case Study
Case: A developer needs real-time notifications for a campus app.
<div id="notifications"></div>
<script>
function connectNotification() {
// WebSocket simulation for notifications
setInterval(() => {
const notifications = [
'Tomorrow's class schedule has been updated',
'New semester registration is now open',
'Graduation announcement'
];
const randomNotif = notifications[Math.floor(Math.random() * notifications.length)];
showNotification(randomNotif);
}, 10000);
}
function showNotification(message) {
const div = document.createElement('div');
div.style.cssText = 'background: #3498db; color: white; padding: 1rem; margin: 0.5rem 0; border-radius: 4px;';
div.textContent = message;
document.getElementById('notifications').prepend(div);
setTimeout(() => div.remove(), 5000);
}
connectNotification();
</script>
Best Practices
- Reconnection: Handle dropped connections
- Heartbeat: Send pings periodically
- Message queue: Store messages when offline
- Security: Use wss:// (WebSocket Secure)
- Fallback: Use polling as a fallback
Summary
WebSocket enables two-way real-time communication. It's perfect for chat, live notifications, and apps that need real-time updates.