Standardowy czat: użytkownik wysyła komunikat, który serwer rozsyła do wszystkich połączonych użytkowników.
Aplikacja została zaimplementowana w oparciu o protokół Websocket z wykorzystaniem modułu Socket.IO
Struktura plików aplikacji podana jest na poniższym obrazku.
. ├── Gruntfile.js ├── package.json ├── public │ ├── css │ │ └── styl.css │ ├── img │ │ ├── bullet_green.png │ │ └── bullet_red.png │ ├── index.html │ └── js │ └── skrypt.js └── serwer.js
Główne pliki w tej implementacji — to: index.html
,script.js
, serwer.js
.
index.html
Ten plik jest wysyłany do klienta bez zmian. Zawiera on podstawowe drzewo DOM strony. Drzewo to będzie uzupełniane i modyfikowane dynamiczne po stronie klienta.
script.js
Ten plik zawiera aplikację kliencką.
serwer.js
W tym pliku jest aplikacja serwerowa.
W aplikacji utworzono dwa serwery: standardowy HTTP oraz serwer Websocket[1]
var express = require('express'); var app = express(); var httpServer = require("http").Server(app); var io = require("socket.io")(httpServer);
Przy połączeniu (zdarzenie connection
) na obiekcie socket
, który odpowiada klientowi, rejestruje się dwa callbacki: na zdarzenie message
(komunikat od klienta) oraz zdarzenie error
.
io.sockets.on("connection", function (socket) { socket.on("message", function (data) { io.sockets.emit("echo", "No tak, tak – dostałem: " + data); }); socket.on("error", function (err) { console.dir(err); }); });
W momencie, kiedy drzewo DOM już jest zbudowano, wywołana jest funkcja, wykonująca następujące czynności:
Otrzymuje dostęp do elementów DOM poprzez odpowiednie zmienne:
var status = document.getElementById("status"); var open = document.getElementById("open"); var close = document.getElementById("close"); var send = document.getElementById("send"); var text = document.getElementById("text"); var message = document.getElementById("message");
Określa obiekt socket
, który będzie odpowiadał za połączenie z serwerem:
var socket;
Ustawia początkowe właściwości elementów DOM:
status.textContent = "Brak połącznia"; close.disabled = true; send.disabled = true;
Po kliknięciu na przycisk „Połącz” (element open
) nawiązuje się nowe połączenie Websocket:
open.addEventListener("click", function (event) { open.disabled = true; if (!socket || !socket.connected) { socket = io({forceNew: true}); }
Oraz ustawia się callbacki na zdarzenia:
connect
— zmiana ustawień elementów:
socket.on('connect', function () { close.disabled = false; send.disabled = false; status.src = "img/bullet_green.png"; console.log('Nawiązano połączenie przez Socket.io'); });
disconnect
— przywrócenie ustawień elementów:
socket.on('disconnect', function () { open.disabled = false; status.src = "img/bullet_red.png"; console.log('Połączenie przez Socket.io zostało zakończone'); });
error
— wyświetlenie komunikatu o błędzie:
socket.on("error", function (err) { message.textContent = "Błąd połączenia z serwerem: '" + JSON.stringify(err) + "'"; });
echo
— wyświetlenie komunikatu, otrzymanego z serwera:
socket.on("echo", function (data) { message.textContent = "Serwer twierdzi, że otrzymał od Ciebie: '" + data + "'"; });
Po kliknięciu na przycisk „Rozłącz” (element close
) połączenia się rozłącza i stosownie zmienia się ustawienia:
close.addEventListener("click", function (event) { close.disabled = true; send.disabled = true; open.disabled = false; message.textContent = ""; socket.io.disconnect(); console.dir(socket); });
Po kliknięciu na przycisk „Wyślij” (element send
) wysyła się tekst komunikatu na serwer.
send.addEventListener("click", function (event) { socket.emit('message', text.value); console.log('Wysłałem wiadomość: ' + text.value); text.value = ""; });
Na serwerze dla tego klienta odpala się zdarzenie message
— wynika to z powyższego kodu.
Nawias zamykający funkcji:
});
[1] Moduł Socket.IO
emuluje protokół Websocket dla przeglądarek, które nie obsługują tego protokołu. Jednak takie przeglądarki są bardzo rzadkie.