Difference between revisions of "Socket.IO"

From CSE330 Wiki
Jump to navigationJump to search
 
(22 intermediate revisions by 4 users not shown)
Line 7: Line 7:
 
Before you install Socket.IO, you need to install [[Node.JS]] and NPM, which is often installed automatically when you install Node.JS.
 
Before you install Socket.IO, you need to install [[Node.JS]] and NPM, which is often installed automatically when you install Node.JS.
  
Once those are ready, installing Socket.IO is as simple as a one-liner NPM command:
+
The NPM package manager is different from many of the package managers we've used in that you need to install remote packages for every project in which you use them.  This means that you need to '''cd''' to the working directory in which you want to keep your Node.JS JavaScript file, ''and then'' run the following command:
  
 
<source lang="bash">
 
<source lang="bash">
$ sudo npm install -g socket.io
+
$ npm install socket.io --save
 
</source>
 
</source>
  
'''Note:''' The ''-g'' means that Socket.IO will be installed "globally" on your instance, so all Node.JS projects will be able to use it.  Had you not used the ''-g'' option, Socket.IO would install in a new local directory called ''node_modules'' and would be accessible to only the project in the current working directory.
+
'''Note:''' If you pass the ''-g'' to ''npm install'', then the package will be installed "globally" on your instance, so all Node.JS projects will be able to use it.
  
 
== Messaging ==
 
== Messaging ==
Line 43: Line 43:
 
<source lang="javascript">
 
<source lang="javascript">
 
// Require the packages we will use:
 
// Require the packages we will use:
var http = require("http"),
+
const http = require("http"),
io = require("socket.io"),
+
    fs = require("fs");
fs = require("fs");
 
  
// Listen for HTTP connections.  This is essentially a miniature static file server that only serves our one file, chat.html:
+
const port = 3456;
var app = http.createServer(function(req, resp){
+
const file = "client.html";
// This callback runs when a new connection is made to our HTTP server.
+
// Listen for HTTP connections.  This is essentially a miniature static file server that only serves our one file, client.html, on port 3456:
fs.readFile("chat.html", function(err, data){
+
const server = http.createServer(function (req, res) {
// This callback runs when the chat.html file has been read from the filesystem.
+
    // This callback runs when a new connection is made to our HTTP server.
if(err) return resp.writeHead(500);
+
 
resp.writeHead(200);
+
    fs.readFile(file, function (err, data) {
resp.end(data);
+
        // This callback runs when the client.html file has been read from the filesystem.
});
+
 
 +
        if (err) return res.writeHead(500);
 +
        res.writeHead(200);
 +
        res.end(data);
 +
    });
 
});
 
});
app.listen(3456);
+
server.listen(port);
  
// Do the Socket.IO magic:
+
// Import Socket.IO and pass our HTTP server object to it.
io.listen(app).sockets.on("connection", function(socket){
+
const socketio = require("socket.io")(http, {
// This callback runs when a new Socket.IO connection is established.
+
    wsEngine: 'ws'
socket.on("message", function(content){
 
// This callback runs when the client sends us a "message" event
 
console.log("message: "+content); // log it to the Node.JS output
 
socket.broadcast.emit("someonesaid", content); // broadcast the message to other users
 
});
 
 
});
 
});
 +
 +
// Attach our Socket.IO server to our HTTP server to listen
 +
const io = socketio.listen(server);
 +
io.sockets.on("connection", function (socket) {
 +
    // This callback runs when a new Socket.IO connection is established.
 +
 +
    socket.on('message_to_server', function (data) {
 +
        // This callback runs when the server receives a new message from the client.
 +
 +
        console.log("message: " + data["message"]); // log it to the Node.JS output
 +
        io.sockets.emit("message_to_client", { message: data["message"] }) // broadcast the message to other users
 +
    });
 +
});
 +
 
</source>
 
</source>
  
The above code makes a simple HTTP server that responds to all connections with the contents of the file "chat.html", which we will make in the next step.  We tell Socket.IO to listen for "message" events, and when it hears one, it should emit a new event called "someone said" back to the connected clients.
+
The above code makes a simple HTTP server that responds to all connections with the contents of the file "client.html", which we will make in the next step.  We tell Socket.IO to listen for "message" events, and when it hears one, it should emit a new event called "someone said" back to the connected clients.
  
 
=== The Chat Client ===
 
=== The Chat Client ===
  
Here is a front-end client that could work with our server, in ''chat.html'':
+
Here is a front-end client that could work with our server, in ''client.html'':
  
 
<source lang="html4strict">
 
<source lang="html4strict">
 +
 
<!DOCTYPE html>
 
<!DOCTYPE html>
 
<html>
 
<html>
<head>
+
  <head>
<title>Chat Client</title>
+
      <script src="/socket.io/socket.io.js"></script>
 +
      <script>
  
<!-- Include the Socket.IO and Ext libraries -->
+
      var socketio = io.connect();
<script src="/socket.io/socket.io.js"></script>
+
      socketio.on("message_to_client",function(data) {
<script src="//cdn.sencha.io/ext-4.1.1-gpl/ext-all-dev.js"></script>
+
        //Append an HR thematic break and the escaped HTML of the new message
 +
        document.getElementById("chatlog").appendChild(document.createElement("hr"));
 +
        document.getElementById("chatlog").appendChild(document.createTextNode(data['message']));
 +
      });
  
<!-- Write our custom code -->
+
      function sendMessage(){
<script>
+
        var msg = document.getElementById("message_input").value;
Ext.DomHelper.useDom = true; // prevent XSS
+
        socketio.emit("message_to_server", {message:msg});
 +
      }
  
var socket = io.connect("http://localhost");
+
      </script>
socket.on("someonesaid", function(content){
+
  </head>
// This callback runs when the server sends us a "someonesaid" event
+
  <body>
Ext.fly("messages").createChild({
+
      <input type=text" id="message_input"/>
tag: "li",
+
      <button onclick="sendMessage()">send</button>
children: [content]
+
      <div id="chatlog"></div>
});
+
  </body>
});
+
</html>
Ext.onReady(function(){
 
Ext.fly("send").on("click", function(){
 
// When the "send" button is clicked, emit a "message" event to the server containing a chat message
 
socket.emit("message", Ext.fly("comment").getValue());
 
});
 
});
 
</script>
 
  
</head>
 
<body>
 
<ul id="messages">
 
</ul>
 
 
<p>
 
<textarea id="comment"></textarea>
 
<button id="send">Send Comment</button>
 
</p>
 
</body>
 
</html>
 
 
</source>
 
</source>
  
Line 123: Line 123:
 
To see this in action, save these two files in the same directory, cd over to the directory, and start the server:
 
To see this in action, save these two files in the same directory, cd over to the directory, and start the server:
  
<source lang="bash">$ node chat.js</source>
+
<source lang="bash">$ node chat-server.js</source>
  
 
Fire up your favorite browser and navigate to http://localhost:3456/.  Open the page in two windows.  Violà: you have your (very basic) chat client!
 
Fire up your favorite browser and navigate to http://localhost:3456/.  Open the page in two windows.  Violà: you have your (very basic) chat client!
Line 129: Line 129:
 
== Resources ==
 
== Resources ==
  
The [http://socket.io/ Socket.IO web site] has concise examples that tell you pretty much all you need to know in order to build a functional Socket.IO web application.
+
The [http://socket.io/ Socket.IO web site] has concise examples that tell you pretty much all you need to know in order to build a functional Socket.IO web application. A helpful discussion on how to use rooms with Socket.IO can be found [https://socket.io/docs/v4/rooms/ here].  
  
 
[[Category:Module 7]]
 
[[Category:Module 7]]

Latest revision as of 20:38, 6 June 2024

AJAX is useful when one-way communication is satisfactory for your web application. However, what happens when you need two-way communication, like a chat client or multiplayer game? AJAX isn't the tool for the job. This is where Socket.IO comes in.

Built to work natively with Node.JS, Socket.IO enables asynchronous, two-way communication between the server and the client. This means that the server can send messages to the client without the client having to ask first, as is the case with AJAX. As you learn Socket.IO, Non-Blocking I/O will become your best friend!

Installing Socket.IO

Before you install Socket.IO, you need to install Node.JS and NPM, which is often installed automatically when you install Node.JS.

The NPM package manager is different from many of the package managers we've used in that you need to install remote packages for every project in which you use them. This means that you need to cd to the working directory in which you want to keep your Node.JS JavaScript file, and then run the following command:

$ npm install socket.io --save

Note: If you pass the -g to npm install, then the package will be installed "globally" on your instance, so all Node.JS projects will be able to use it.

Messaging

Socket.IO works by having clients send messages to the server and the server send messages to clients. For example, consider the code:

// Computer A:
socket.emit("info", {
	"hello": "world"
});

// Computer B:
socket.on("info", function (data) {
	console.log(data.hello);
});

Computer A could be either the client or the server, and Computer B would be the other. When socket.emit(name, data) is called on either end, the callback function in socket.on that listens for the message named name is called with the data from socket.emit.

A First Socket.IO Application: Chat Server and Client

Building a chat client is surprising simple using Socket.IO and Node.JS, and it gives great insight into the workings of Socket.IO. Take the time to understand how this example works, and ask questions; if you understand this, the group portion will be easy!

The Chat Server

You can make a file called chat-server.js with the following code:

// Require the packages we will use:
const http = require("http"),
    fs = require("fs");

const port = 3456;
const file = "client.html";
// Listen for HTTP connections.  This is essentially a miniature static file server that only serves our one file, client.html, on port 3456:
const server = http.createServer(function (req, res) {
    // This callback runs when a new connection is made to our HTTP server.

    fs.readFile(file, function (err, data) {
        // This callback runs when the client.html file has been read from the filesystem.

        if (err) return res.writeHead(500);
        res.writeHead(200);
        res.end(data);
    });
});
server.listen(port);

// Import Socket.IO and pass our HTTP server object to it.
const socketio = require("socket.io")(http, {
    wsEngine: 'ws'
});

// Attach our Socket.IO server to our HTTP server to listen
const io = socketio.listen(server);
io.sockets.on("connection", function (socket) {
    // This callback runs when a new Socket.IO connection is established.

    socket.on('message_to_server', function (data) {
        // This callback runs when the server receives a new message from the client.

        console.log("message: " + data["message"]); // log it to the Node.JS output
        io.sockets.emit("message_to_client", { message: data["message"] }) // broadcast the message to other users
    });
});

The above code makes a simple HTTP server that responds to all connections with the contents of the file "client.html", which we will make in the next step. We tell Socket.IO to listen for "message" events, and when it hears one, it should emit a new event called "someone said" back to the connected clients.

The Chat Client

Here is a front-end client that could work with our server, in client.html:

<!DOCTYPE html>
<html>
   <head>
      <script src="/socket.io/socket.io.js"></script>
      <script>

      var socketio = io.connect();
      socketio.on("message_to_client",function(data) {
         //Append an HR thematic break and the escaped HTML of the new message
         document.getElementById("chatlog").appendChild(document.createElement("hr"));
         document.getElementById("chatlog").appendChild(document.createTextNode(data['message']));
      });

      function sendMessage(){
         var msg = document.getElementById("message_input").value;
         socketio.emit("message_to_server", {message:msg});
      }

      </script>
   </head>
   <body>
      <input type=text" id="message_input"/>
      <button onclick="sendMessage()">send</button>
      <div id="chatlog"></div>
   </body>
</html>

Note: This example passes strings as the event data, but you can pass any JavaScript datatype, including object literals.

To see this in action, save these two files in the same directory, cd over to the directory, and start the server:

$ node chat-server.js

Fire up your favorite browser and navigate to http://localhost:3456/. Open the page in two windows. Violà: you have your (very basic) chat client!

Resources

The Socket.IO web site has concise examples that tell you pretty much all you need to know in order to build a functional Socket.IO web application. A helpful discussion on how to use rooms with Socket.IO can be found here.