# Nodejs

## **Real-time Communication with** [**Socket.io**](http://Socket.io)

### **Introduction**

In this module, we will explore real-time communication on the web using [Socket.io](http://Socket.io). You will learn how to create a simple chat application that allows users to send and receive messages instantly.

### **Objectives**

By the end of this module, you will be able to:

* Understand the basics of WebSockets and [Socket.io](http://Socket.io)
    
* Set up a Node.js server with [Socket.io](http://Socket.io)
    
* Create a client-side application that communicates with the server in real-time
    
* Implement a basic chat application with real-time messaging
    

### **Prerequisites**

Before starting this module, you should have:

* Basic understanding of JavaScript
    
* Familiarity with Node.js and Express.js
    
* Basic knowledge of HTML and CSS
    

### **1\. Understanding WebSockets and** [**Socket.io**](http://Socket.io)

**WebSockets** are a communication protocol that provides full-duplex communication channels over a single TCP connection. This allows for persistent, bi-directional communication between the client and server.

[**Socket.io**](http://Socket.io) is a JavaScript library that simplifies real-time, bi-directional communication between web clients and servers. It uses WebSockets under the hood but provides additional features like automatic reconnection, broadcasting, and fallbacks to other protocols when WebSockets are not available.

### **2\. Setting Up the Server**

Let's start by setting up a Node.js server with Express and [Socket.io](http://Socket.io).

**Step 1: Initialize the Project**

1. **Create a new directory for your project and navigate into it:**
    
    ```basic
    shCopy codemkdir socketio-chat
    cd socketio-chat
    ```
    
    This creates a new directory called `socketio-chat` and navigates into it.
    
2. **Initialize a new Node.js project:**
    
    ```basic
    shCopy codenpm init -y
    ```
    
    This command creates a `package.json` file with default settings.
    
3. **Install the required packages:**
    
    ```basic
    shCopy codenpm install express socket.io
    ```
    
    This installs the `express` and [`socket.io`](http://socket.io) packages, which we will use to create the server and handle real-time communication.
    

**Step 2: Create the Server**

Create a file named `server.js` and set up a basic Express server with [Socket.io](http://Socket.io):

```basic
javascriptCopy code// Import the Express library
const express = require('express');

// Import the http module to create a server
const http = require('http');

// Import the Socket.io library
const socketIo = require('socket.io');

// Create an instance of the Express application
const app = express();

// Create an HTTP server using the Express app
const server = http.createServer(app);

// Initialize a new instance of Socket.io by passing the HTTP server object
const io = socketIo(server);

// Serve static files from the 'public' directory
app.use(express.static('public'));

// Listen for clients connecting to the Socket.io server
io.on('connection', (socket) => {
  console.log('A user connected'); // Log a message when a user connects

  // Listen for the client disconnecting
  socket.on('disconnect', () => {
    console.log('User disconnected'); // Log a message when a user disconnects
  });

  // Listen for 'chat message' events from the client
  socket.on('chat message', (msg) => {
    // Broadcast the received message to all connected clients
    io.emit('chat message', msg);
  });
});

// Define the port number for the server to listen on
const PORT = process.env.PORT || 3000;

// Start the server and listen on the specified port
server.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});
```

### **3\. Creating the Client**

Next, we'll set up the client-side application.

**Step 3: Set Up the Client-side**

1. **Create a** `public` **directory in your project root.**
    
    ```basic
    shCopy codemkdir public
    ```
    
2. **Within the** `public` **directory, create an** `index.html` file:
    
    ```basic
    htmlCopy code<!-- public/index.html -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Socket.io Chat</title>
      <style>
        body { font-family: Arial, sans-serif; } /* Set the font for the body */
        #messages { list-style-type: none; padding: 0; } /* Remove list styles for messages */
        #messages li { padding: 8px; margin-bottom: 10px; background-color: #f4f4f4; } /* Style for each message */
        #form { display: flex; } /* Flexbox for form layout */
        #input { flex: 1; padding: 10px; } /* Input field styling */
        #send { padding: 10px; } /* Send button styling */
      </style>
    </head>
    <body>
      <!-- Unordered list to display chat messages -->
      <ul id="messages"></ul>
      <!-- Form for submitting new chat messages -->
      <form id="form" action="">
        <!-- Input field for entering a new message -->
        <input id="input" autocomplete="off" />
        <!-- Submit button for sending the message -->
        <button id="send">Send</button>
      </form>
    
      <!-- Include the Socket.io client library -->
      <script src="/socket.io/socket.io.js"></script>
      <script>
        // Connect to the Socket.io server
        const socket = io();
    
        // Get the form and input elements from the DOM
        const form = document.getElementById('form');
        const input = document.getElementById('input');
    
        // Listen for the form submission event
        form.addEventListener('submit', function(e) {
          e.preventDefault(); // Prevent the form from submitting the traditional way
          if (input.value) { // Check if the input field is not empty
            // Emit the 'chat message' event to the server with the input value
            socket.emit('chat message', input.value);
            input.value = ''; // Clear the input field
          }
        });
    
        // Listen for 'chat message' events from the server
        socket.on('chat message', function(msg) {
          // Create a new list item for the message
          const item = document.createElement('li');
          item.textContent = msg; // Set the text content of the list item to the message
          document.getElementById('messages').appendChild(item); // Add the list item to the messages list
          window.scrollTo(0, document.body.scrollHeight); // Scroll to the bottom of the page
        });
      </script>
    </body>
    </html>
    ```
    

### **4\. Implementing Real-time Communication**

In `server.js`, we set up [Socket.io](http://Socket.io) to handle connection events, disconnection events, and custom events (like `chat message`). This allows the server to broadcast messages to all connected clients.

On the client side, we set up event listeners for form submission to send messages to the server and update the chat log when messages are received from the server.

### **5\. Adding Basic Chat Functionality**

Now we have a basic chat application where users can send and receive messages in real-time.

**Run the Server**

Start the server by running:

```basic
shCopy codenode server.js
```

Open your browser and navigate to [`http://localhost:3000`](http://localhost:3000). Open multiple tabs to simulate multiple users and test the real-time chat functionality.

### **Additional Exercises**

1. **Usernames**: Add functionality to allow users to set their usernames and display them alongside their messages.
    
2. **Message Timestamps**: Add timestamps to messages to display when each message was sent.
    
3. **Styling**: Improve the chat interface with better CSS styling.
    

### **Example Enhancements**

**Adding Usernames**

Modify the client-side JavaScript to include a prompt for the username when the user connects:

```basic
javascriptCopy code// public/index.html (within the <script> tag)
const username = prompt('Enter your username:');
if (username) {
  socket.emit('set username', username);
}

form.addEventListener('submit', function(e) {
  e.preventDefault(); // Prevent the form from submitting the traditional way
  if (input.value) { // Check if the input field is not empty
    // Emit the 'chat message' event to the server with the username and message
    socket.emit('chat message', { username: username, message: input.value });
    input.value = ''; // Clear the input field
  }
});

socket.on('chat message', function(data) {
  // Create a new list item for the message
  const item = document.createElement('li');
  item.textContent = `${data.username}: ${data.message}`; // Set the text content of the list item to the message with username
  document.getElementById('messages').appendChild(item); // Add the list item to the messages list
  window.scrollTo(0, document.body.scrollHeight); // Scroll to the bottom of the page
});
```

Update the server to handle the `set username` and include the username in the `chat message` event:

```basic
javascriptCopy code// server.js (additional code)
io.on('connection', (socket) => {
  let username = 'Anonymous';

  // Listen for 'set username' events from the client
  socket.on('set username', (name) => {
    username = name; // Set the username variable to the received name
  });

  // Listen for 'chat message' events from the client
  socket.on('chat message', (msg) => {
    // Broadcast the received message to all connected clients, including the username
    io.emit('chat message', { username: username, message: msg });
  });
});
```

**Adding Message Timestamps**

Modify the client-side JavaScript to include timestamps:

```basic
javascriptCopy code// public/index.html (within the <script> tag)
form.addEventListener('submit', function(e) {
  e.preventDefault(); // Prevent the form from submitting the traditional way
  if (input.value) { // Check if the input field is not empty
    const timestamp = new Date().toLocaleTimeString(); // Get the current time as a timestamp
    // Emit the 'chat message' event to the server with the username, message, and timestamp
    socket.emit('chat message', { username: username, message: input.value, timestamp: timestamp });
    input.value = ''; // Clear the input field
  }
});

socket.on('chat message', function(data) {
  // Create a new list item for the message
  const item = document.createElement('li');
  // Set the text content of the list item to the message with timestamp and username
  item.textContent = `[${data.timestamp}] ${data.username}: ${data.message}`;
  document.getElementById('messages').appendChild(item); // Add the list item to the messages list
  window.scrollTo(0, document.body.scrollHeight); // Scroll to the bottom of the page
});
```

### **Conclusion**

In this module, you learned how to create a simple real-time chat application using [Socket.io](http://Socket.io). You set up a Node.js server with [Socket.io](http://Socket.io), created a client-side application, and implemented real-time communication between the server and clients. By extending the basic functionality, you can continue to build more complex real-time applications.
