iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
Formations
Node.js / HTML · Débutant

WebSocket

Comprendre le protocole WebSocket de zéro et construire un système de chat complet : connexion, utilisateurs en mémoire, messages privés et groupes — sans base de données.

Node.jswsJavaScriptHTML
01Le protocole WebSocket02Premier serveur WebSocket03Gérer les utilisateurs en mémoire04Chat global et broadcast05Messages privés06Groupes et rooms07Interface client complète
Chapitre 3·25 min

Gérer les utilisateurs en mémoire

Une connexion WebSocket est anonyme par défaut. Le serveur sait qu'un client est connecté, pas qui il est. Pour un chat, il faut associer chaque socket à un username et maintenir ce registre en mémoire tant que le serveur tourne.

Le registre des utilisateurs

Un Map JavaScript fait exactement ce dont on a besoin : clé = username, valeur = socket.

server.js
const { WebSocketServer, WebSocket } = require('ws')
 
const wss = new WebSocketServer({ port: 8080 })
 
// username → socket
const users = new Map()
 
wss.on('connection', (socket) => {
  // username stocké directement sur le socket pour y accéder partout
  socket.username = null
 
  socket.on('message', (data) => {
    let msg
    try {
      msg = JSON.parse(data.toString())
    } catch {
      return
    }
 
    handleMessage(socket, msg)
  })
 
  socket.on('close', () => {
    if (socket.username) {
      users.delete(socket.username)
      broadcast({ type: 'system', content: `${socket.username} a quitté le chat` })
      console.log(`${socket.username} déconnecté`)
    }
  })
})
 
function handleMessage(socket, msg) {
  switch (msg.type) {
    case 'register':
      registerUser(socket, msg)
      break
    default:
      socket.send(JSON.stringify({ type: 'error', content: 'Identifiez-vous d\'abord' }))
  }
}

L'inscription

server.js
function registerUser(socket, msg) {
  const username = (msg.username || '').trim()
 
  if (!username) {
    socket.send(JSON.stringify({ type: 'error', content: 'Username vide' }))
    return
  }
 
  if (users.has(username)) {
    socket.send(JSON.stringify({ type: 'error', content: 'Username déjà pris' }))
    return
  }
 
  // Associer le username à ce socket
  socket.username = username
  users.set(username, socket)
 
  socket.send(JSON.stringify({
    type: 'registered',
    content: `Bienvenue ${username} !`,
    users: [...users.keys()],
  }))
 
  broadcast(
    { type: 'system', content: `${username} a rejoint le chat` },
    socket  // exclure l'expéditeur
  )
 
  console.log(`${username} connecté. Utilisateurs en ligne : ${users.size}`)
}

Broadcast utilitaire

server.js
function broadcast(msg, exclude = null) {
  const data = JSON.stringify(msg)
  wss.clients.forEach((client) => {
    if (client !== exclude && client.readyState === WebSocket.OPEN) {
      client.send(data)
    }
  })
}

exclude permet d'éviter d'envoyer un message à l'émetteur lui-même — utile pour les notifications système comme "X a rejoint".

Lister les utilisateurs en ligne

server.js
// Ajouter dans handleMessage, case 'list':
case 'list':
  socket.send(JSON.stringify({
    type: 'list',
    users: [...users.keys()],
  }))
  break
// Client envoie :
ws.send(JSON.stringify({ type: 'list' }))
 
// Serveur répond avec :
// { type: 'list', users: ['alice', 'bob', 'carol'] }

Protéger les actions non authentifiées

Avant de traiter tout autre type de message, vérifier que l'utilisateur est inscrit :

server.js
function handleMessage(socket, msg) {
  if (msg.type === 'register') {
    registerUser(socket, msg)
    return
  }
 
  // Tout le reste nécessite d'être identifié
  if (!socket.username) {
    socket.send(JSON.stringify({ type: 'error', content: 'Non identifié' }))
    return
  }
 
  switch (msg.type) {
    case 'list':
      socket.send(JSON.stringify({ type: 'list', users: [...users.keys()] }))
      break
    default:
      socket.send(JSON.stringify({ type: 'error', content: 'Type de message inconnu' }))
  }
}

Tester avec deux onglets

Ouvrir client.html dans deux onglets du navigateur. Dans la console de chaque onglet :

Onglet 1 :

ws.send(JSON.stringify({ type: 'register', username: 'alice' }))

Onglet 2 :

ws.send(JSON.stringify({ type: 'register', username: 'bob' }))

L'onglet 1 reçoit une notification système "bob a rejoint le chat". Le serveur affiche dans son terminal les connexions au fil des inscriptions.

État du serveur à ce stade

Map users:
  'alice' → WebSocket { username: 'alice', readyState: 1 }
  'bob'   → WebSocket { username: 'bob',   readyState: 1 }

Chaque entrée de la Map pointe vers le socket live du client. Pour envoyer un message à Alice, il suffit de faire users.get('alice').send(...).


Le registre est en place. Le chapitre suivant ajoute le chat global — diffusion de messages à tous les utilisateurs connectés.

Précédent
Premier serveur WebSocket
Suivant
Chat global et broadcast

Développeur fullstack passionné. J'apprends en construisant et je documente tout — front, back, outils. Le code s'apprend mieux en public.

Naviguer

IndexTous les articlesFormationsProfilOutilsBibliothech

Ailleurs

GitHub RSS

Newsletter

Les articles, libs et découvertes. Une fois par semaine, pas plus.

© 2026 William LoreeConçu & codé à la main