Programmation réseau en Kotlin : de la théorie à la pratique
Le monde moderne est un monde d'applications interconnectées. Qu'il s'agisse d'un chatbot, d'un jeu en ligne ou d'une architecture de microservices, tout repose sur les interactions réseau. Et si autrefois la programmation réseau était exclusivement associée à Java ou C++, aujourd'hui Kotlin fait une entrée remarquée sur la scène.
Pourquoi Kotlin ? Ce langage n'est pas simplement un « Java moderne ». Il a intégré le meilleur du monde JVM, en ajoutant de la concision, de la sécurité et un puissant support de l'asynchronisme grâce aux coroutines. Dans cet article, nous allons voir comment écrire de la programmation réseau en Kotlin — des sockets classiques aux solutions élégantes avec les coroutines. Vous apprendrez à créer votre propre serveur TCP, à envoyer un paquet UDP et à ne pas perdre la tête avec le multithreading.
Pourquoi Kotlin est-il adapté aux tâches réseau ?
Avant de plonger dans le code, voyons pourquoi Kotlin est un excellent choix pour la programmation réseau :
- Compatibilité totale avec Java : vous pouvez utiliser tout l'arsenal de
java.net,java.nioet des frameworks populaires (Netty, Ktor). - Coroutines : le code asynchrone ressemble à du code synchrone. Fini l'enfer des callbacks.
- Sécurité null : moins de risques d'obtenir une
NullPointerExceptionlors du travail avec les flux de données. - Extensions fonctionnelles : des fonctions d'extension pratiques pour travailler avec les octets et les chaînes de caractères.
Nous commencerons par les sockets de base (comme dans le bon vieux Java), puis nous passerons à une approche plus moderne avec les coroutines.
Les bases : serveur et client TCP en Kotlin
Commençons par les classiques — les connexions TCP. En Kotlin, nous utilisons les mêmes classes ServerSocket et Socket, mais avec une syntaxe plus propre.
Écrire un simple serveur TCP echo
Notre serveur recevra les messages du client et les renverra (echo).
import java.io.BufferedReaderimport java.io.InputStreamReaderimport java.io.PrintWriterimport java.net.ServerSocket
fun main() { val port = 8080 val serverSocket = ServerSocket(port) println("Serveur démarré sur le port $port")
while (true) { // Blocage en attente d'un client val clientSocket = serverSocket.accept() println("Client connecté : ${clientSocket.inetAddress.hostAddress}")
// Traitement du client dans un thread séparé (à des fins pédagogiques) Thread { try { val input = BufferedReader(InputStreamReader(clientSocket.inputStream)) val output = PrintWriter(clientSocket.outputStream, true)
var message: String? while (input.readLine().also { message = it } != null) { println("Reçu : $message") output.println("Echo : $message") } } catch (e: Exception) { println("Erreur : ${e.message}") } finally { clientSocket.close() } }.start() }}Notez que nous utilisons Thread { ... }.start(). Cela fonctionne, mais pour la production, il est préférable d'utiliser un pool de threads ou des coroutines (nous y reviendrons plus tard).
Client pour le serveur echo
Écrivons maintenant un client qui se connecte au serveur et envoie des messages :
import java.io.BufferedReaderimport java.io.InputStreamReaderimport java.io.PrintWriterimport java.net.Socket
fun main() { val host = "localhost" val port = 8080
try { val socket = Socket(host, port) val output = PrintWriter(socket.outputStream, true) val input = BufferedReader(InputStreamReader(socket.inputStream))
// Envoi des messages val messages = listOf("Bonjour, serveur !", "Comment ça va ?", "Au revoir !")