Skip to main content

Echo WebSocket Messages

Introduction

WebSockets provide a powerful way to establish persistent, two-way connections between a client and a server. One of the fundamental operations in WebSocket communication is sending and receiving messages. In this tutorial, we'll explore how to create a simple "echo" system where messages sent to the server are echoed back to the client, demonstrating the core principles of WebSocket message handling.

An echo system is an excellent starting point for understanding WebSockets because:

  • It demonstrates the full communication cycle
  • It's easy to visualize and debug
  • It forms the foundation for more complex WebSocket applications

Setting Up a WebSocket Connection

Before we can send and receive messages, we need to establish a WebSocket connection. Here's how to create a basic connection in JavaScript:

javascript
// Creating a new WebSocket connection
const socket = new WebSocket('ws://localhost:8080');

// Connection opened
socket.addEventListener('open', (event) => {
console.log('Connected to WebSocket server');
});

// Listen for errors
socket.addEventListener('error', (event) => {
console.error('WebSocket error:', event);
});

// Connection closed
socket.addEventListener('close', (event) => {
console.log('Disconnected from WebSocket server');
});

Sending Messages

Once the connection is established, we can send messages to the server using the send() method. Messages can be strings, ArrayBuffers, Blobs, or ArrayBufferViews.

javascript
// Function to send a message
function sendMessage(message) {
// Check if the connection is open
if (socket.readyState === WebSocket.OPEN) {
socket.send(message);
console.log('Message sent:', message);
} else {
console.error('Connection is not open');
}
}

// Example: Send a message when a button is clicked
document.getElementById('sendButton').addEventListener('click', () => {
const messageInput = document.getElementById('messageInput');
sendMessage(messageInput.value);
messageInput.value = ''; // Clear the input field
});

Receiving Echo Messages

When the server receives our message and echoes it back, we need to listen for the incoming message and handle it appropriately:

javascript
// Listen for messages from the server
socket.addEventListener('message', (event) => {
const message = event.data;
console.log('Message from server:', message);

// Display the message in the UI
const messagesContainer = document.getElementById('messages');
const messageElement = document.createElement('div');
messageElement.textContent = `Echo: ${message}`;
messagesContainer.appendChild(messageElement);
});

Complete Client-Side Echo Example

Here's a complete example of an echo client that sends messages to a WebSocket server and displays the echoed responses:

javascript
// DOM elements
const messagesContainer = document.getElementById('messages');
const messageInput = document.getElementById('messageInput');
const sendButton = document.getElementById('sendButton');
const connectionStatus = document.getElementById('status');

// Create WebSocket connection
const socket = new WebSocket('ws://localhost:8080');

// Connection opened
socket.addEventListener('open', (event) => {
connectionStatus.textContent = 'Connected';
connectionStatus.className = 'connected';
console.log('Connected to WebSocket server');
});

// Listen for messages
socket.addEventListener('message', (event) => {
const message = event.data;
console.log('Message from server:', message);

// Display the message
const messageElement = document.createElement('div');
messageElement.className = 'received-message';
messageElement.textContent = `Echo: ${message}`;
messagesContainer.appendChild(messageElement);

// Auto-scroll to the bottom
messagesContainer.scrollTop = messagesContainer.scrollHeight;
});

// Connection closed
socket.addEventListener('close', (event) => {
connectionStatus.textContent = 'Disconnected';
connectionStatus.className = 'disconnected';
console.log('Disconnected from WebSocket server');
});

// Connection error
socket.addEventListener('error', (event) => {
connectionStatus.textContent = 'Error';
connectionStatus.className = 'error';
console.error('WebSocket error:', event);
});

// Send message function
function sendMessage() {
const message = messageInput.value;
if (message && socket.readyState === WebSocket.OPEN) {
socket.send(message);

// Display sent message
const messageElement = document.createElement('div');
messageElement.className = 'sent-message';
messageElement.textContent = `Sent: ${message}`;
messagesContainer.appendChild(messageElement);

// Clear input and focus
messageInput.value = '';
messageInput.focus();

// Auto-scroll
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
}

// Send message on button click
sendButton.addEventListener('click', sendMessage);

// Send message on Enter key
messageInput.addEventListener('keypress', (event) => {
if (event.key === 'Enter') {
sendMessage();
}
});

Here's the corresponding HTML structure:

html
<div class="websocket-container">
<div class="status-bar">
Status: <span id="status">Connecting...</span>
</div>

<div id="messages" class="messages-container"></div>

<div class="input-container">
<input type="text" id="messageInput" placeholder="Type a message..." />
<button id="sendButton">Send</button>
</div>
</div>

Building a Simple Echo Server

To complete our echo system, we need a server that receives messages and echoes them back. Here's a simple Node.js WebSocket server using the ws library:

javascript
const WebSocket = require('ws');

// Create a WebSocket server
const wss = new WebSocket.Server({ port: 8080 });

// Connection handler
wss.on('connection', (ws) => {
console.log('Client connected');

// Message handler
ws.on('message', (message) => {
console.log(`Received: ${message}`);

// Echo the message back to the client
ws.send(message.toString());
});

// Connection close handler
ws.on('close', () => {
console.log('Client disconnected');
});

// Send a welcome message
ws.send('Welcome to the WebSocket Echo Server!');
});

console.log('WebSocket Echo Server running on ws://localhost:8080');

To use this server:

  1. Install Node.js if you haven't already
  2. Create a new project folder and initialize it with npm init -y
  3. Install the WebSocket package with npm install ws
  4. Save the server code in a file named server.js
  5. Run the server with node server.js

Message Types and Formats

WebSockets support different types of messages:

  1. Text Messages: Most common format, using UTF-8 encoded strings.
  2. Binary Messages: Used for sending binary data like images or files.

For our echo example, we're using text messages, but here's how you can handle binary data:

javascript
// Sending binary data
const binaryData = new Uint8Array([1, 2, 3, 4, 5]);
socket.send(binaryData.buffer);

// Receiving binary data
socket.binaryType = 'arraybuffer'; // Set this before receiving binary
socket.addEventListener('message', (event) => {
if (typeof event.data === 'string') {
console.log('Received text message:', event.data);
} else {
const binaryData = new Uint8Array(event.data);
console.log('Received binary message:', binaryData);
}
});

Real-World Application: Chat Echo Bot

Let's extend our example to create a simple chat bot that echoes messages with a small twist - it adds "Echo Bot says: " to the beginning of each message:

javascript
// On the server side
wss.on('connection', (ws) => {
console.log('Client connected to echo bot');

ws.on('message', (message) => {
console.log(`Received: ${message}`);

// Echo with a bot prefix
setTimeout(() => {
ws.send(`Echo Bot says: ${message.toString()}`);
}, 1000); // Add a delay to simulate thinking
});

ws.on('close', () => {
console.log('Client disconnected from echo bot');
});

ws.send('Echo Bot: Hello! Type something and I will echo it back!');
});

This simple modification shows how easy it is to transform messages before echoing them back, which is a fundamental pattern in more complex WebSocket applications.

Debugging WebSocket Messages

When working with WebSockets, debugging can be challenging. Here are some tips:

  1. Use Browser DevTools: In Chrome or Firefox, go to the Network tab and filter by "WS" to see WebSocket connections and messages.

  2. Add Logging: Always log sent and received messages on both client and server sides.

  3. Test with Simple Messages: Start with simple string messages before moving to more complex data structures.

  4. Validate Message Format: If using JSON, ensure your messages are valid:

javascript
// Sending JSON data
function sendJsonMessage(data) {
try {
const jsonString = JSON.stringify(data);
socket.send(jsonString);
console.log('Sent JSON:', data);
} catch (error) {
console.error('Error converting to JSON:', error);
}
}

// Receiving JSON data
socket.addEventListener('message', (event) => {
try {
const data = JSON.parse(event.data);
console.log('Received JSON:', data);
} catch (error) {
console.log('Received raw message (not JSON):', event.data);
}
});

Summary

In this tutorial, we've explored the fundamentals of WebSocket messaging by building a simple echo system:

  1. We learned how to establish WebSocket connections
  2. We implemented sending messages to a WebSocket server
  3. We handled receiving echo messages from the server
  4. We built a complete client-side interface for WebSocket communication
  5. We created a simple echo server in Node.js
  6. We explored different message types and formats
  7. We extended our example to create a simple echo bot
  8. We covered debugging techniques for WebSocket messages

Echo systems are the perfect starting point for WebSocket development because they demonstrate the complete communication cycle. From this foundation, you can build more complex applications like chat systems, real-time dashboards, collaborative editors, and multiplayer games.

Exercises

  1. Basic Echo: Modify the echo server to convert all messages to uppercase before sending them back.

  2. Echo with Delay: Implement a feature where the server waits for a random time (1-3 seconds) before echoing messages to simulate network latency.

  3. JSON Echo: Extend the echo system to accept JSON objects with a "command" field, and respond differently based on the command.

  4. Echo History: Modify the client to store all sent messages and their echoes, and implement a button to display the message history.

  5. Multi-Client Echo: Enhance the server to broadcast received messages to all connected clients, creating a simple group chat application.

Additional Resources

Happy WebSocket messaging!



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)