Dans l'informatique, tout comme dans la société, existens des consommateurs et des producteurs. Ces premiers consomment ce que produisent ces derniers. Le plus souvent, le produit commun pour les deux sera un service. Pour le mettre en place en Java, on peut utiliser les sockets, disponibles dans le package java.net.
Qu'est-ce que c'est un Socket sous Java
Le socket est un point final dans la communication entre 2 programmes lancés dans un réseau. Il est lié à un numéro de port. Grâce à cela, Transmission Control Protocol (TCP) peut identifier l'application à qui les données envoyées par le client sont destinées. Le socket peut être identifié par la combinaison de son adresse IP et du numéro de port.
Les deux participants de la communication sont souvent un client et un serveur. D'habitude le premier envoie une requête et puis traite la réponse. Elle est retournée par le serveur, en fonction des données envoyées.
Le serveur tourne sur une machine spécifique. Il possède un socket qui est lié à un numéro de port précis. Le serveur attend alors que le client se connecte à lui. Ensuite il réagit en fonction des requêtes envoyées. Sa réaction est possible grâce à l'écoute du numéro de port.
Le client connaît donc le nom de l'hôte de la machine ainsi que le numéro de port qu'écoute le serveur. Le schéma de connexion peut donc se résumer à des étapes suivantes :
- Le serveur, lié à un numéro de port, est lancé. Il reste actif et vérifie à chaque fois si aucune nouvelle requête n'est lui est soumise.
- Le client prend connaissance de la localisation du serveur (le nom de l'hôte et le numéro de port). Il tente à établir la connexion.
- Le serveur reçoit la requête et assigne le client à un numéro de port local. Ce numéro sera utilisé pendant la connexion.
- Quand la demande est acceptée, le serveur récupère un nouveau socket. Ensuite son socket est attaché à l'adresse et au port du client. Le nouveau socket est récupéré pour pouvoir continuer à écouter le socket original.
- Du côté client, un socket est également créé pour faciliter la communication du client avec le serveur.
Exemple d'un socket en Java
Tout d'abord on va créer un serveur capable de traiter une seule requête du client et afficher à la fin les données reçues. Le voici :
import java.net.ServerSocket; import java.net.Socket; import java.io.PrintWriter; import java.io.IOException; import java.io.BufferedReader; import java.io.InputStreamReader; public class SocketServer { private boolean isRunning = true; public static void main(String[] args) { SocketServer socketServer = new SocketServer(); socketServer.startSocket(); } public void startSocket() { ServerSocket serverSocket = null; Socket socket = null; try { serverSocket = new ServerSocket(1111); System.out.println("Server socket created"); socket = serverSocket.accept(); System.out.println("Socket accepted"); while (isRunning) { BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println("Receiving data from user : " + inputLine); } isRunning = false; } } catch (IOException ioe) { System.out.println("An IOException occured : " + ioe.getMessage()); } finally { System.out.println("Closing client connection"); try { if (socket != null) socket.close(); } catch (Exception socketEx) { System.out.println("An exception occured on closing socket : " + socketEx.getMessage()); } try { System.out.println("Closing server connection"); if (serverSocket != null) serverSocket.close(); } catch (Exception serverSocketEx) { System.out.println("An exception occured on closing socket : " + serverSocketEx.getMessage()); } } } }
Le code commence avec l'initialisation du serveur sur le port 1111. Ensuite on crée l'instance de la classe Socket qui joue le rôle du client qui communique avec le programme qui se connecte au serveur (SocketClient ci-dessous). Ensuite on effectue toutes les opérations standardes sur les données reçues par le serveur. Elles sont ensuite affichées sur l'écran. La connexion est alors terminée.
Et maintenant le code du client qui, aussi une seule fois, peut envoyer des données au serveur :
import java.net.Socket; import java.io.InputStreamReader; import java.io.BufferedReader; import java.io.Console; import java.io.PrintWriter; public class SocketClient { public static void main(String[] args) { Console console = System.console(); System.out.println("Console found : " + console); String login = console.readLine("Your login : "); try { System.out.println("Connecting with login : " + login); Socket socket = new Socket("127.0.0.1", 1111); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); out.println(login); out.flush(); out.close(); socket.close(); } catch (Exception e) { System.out.println("An exception occured : " + e.getMessage()); } } }
Le client demande d'abord à l'utilisateur de saisir son login. Cette chaîne de caractères est ensuite transféré au serveur grâce au streaming sortant de l'instance du Socket.
Après l'exécution du serveur d'abord et du client après, on verra :
java SocketServer Server socket created java SocketClient Your login : bartosz Connecting with login : bartosz // SocketServer after receiving the data from SocketClient Socket accepted Receiving data from user : bartosz Closing client connection Closing server connection
Question-réponse dans sockets en Java
Modifiant maintenant notre code du paragraphe suivant afin qu'il puisse gérer les interactions entre le serveur et le client. La spécification du code est la suivante. Au tout début l'utilisateur déclenche la connexion au serveur. Celui-ci demande au client de taper un mot. Une fois ce mot tapé, le serveur répond avec le même mot, mais écrit de la dernière à la première lettre. Le serveur utilisera ainsi une connexion persistante.
Voici le code du serveur :
public class SocketClient { private ObjectOutputStream output eee= null; private ObjectInputStream in = null; public static void main(String[] args) { SocketClient client = new SocketClient(); client.connect(); } public void connect() { Console console = System.console(); System.out.println("Console found : " + console); Socket socket = null; try { socket = new Socket("127.0.0.1", 1111); output = new ObjectOutputStream(socket.getOutputStream()); in = new ObjectInputStream(socket.getInputStream()); String message; do { String serverMessage = (String) in.readObject(); System.out.println(serverMessage); message = console.readLine("Your message : "); output.writeObject(message); output.flush(); } while (!message.equals("q")); } catch (Exception e) { System.out.println("An exception occured : " + e.getMessage()); } finally { try { System.out.println("Closing Socket"); if (socket != null) socket.close(); if (in != null) in.close(); if (output != null) output.close(); } catch (Exception e) { System.out.println("An exception occured on closing socket : " + e.getMessage()); } } } }
Et maintenant l'honneur au client :
public class SocketServer { private Socket socket = null; private ObjectOutputStream output eee= null; private ObjectInputStream in = null; public static void main(String[] args) { SocketServer socketServer = new SocketServer(); while (true) socketServer.startSocket(); } public void startSocket() { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(1111); System.out.println("Server socket created"); } catch (Exception e) { System.out.println("An error occured on creating server socket : " + e.getMessage()); } try { socket = serverSocket.accept(); System.out.println("Socket accepted"); output = new ObjectOutputStream(socket.getOutputStream()); output.flush(); in = new ObjectInputStream(socket.getInputStream()); output.writeObject("> Connected"); output.flush(); String message = ""; do { try { message = (String) in.readObject(); System.out.println("< " + message); message = createServerResponse(message); System.out.println("> " + message); output.writeObject("> " + message); output.flush(); } catch (Exception e) { System.out.println("An exception occured on sending message to client : " + e.getMessage()); } } while (!message.equals("q")); } catch (IOException ioe) { System.out.println("An IOException occured : " + ioe.getMessage()); } finally { try { if (output != null) output.close(); if (in != null) in.close(); if (socket != null) socket.close(); } catch (Exception serverSocketEx) { System.out.println("An exception occured on closing socket : " + serverSocketEx.getMessage()); } } try { System.out.println("Closing server connection"); if (serverSocket != null) serverSocket.close(); } catch (Exception socketEx) { System.out.println("An exception occured on closing socket : " + socketEx.getMessage()); } } private String createServerResponse(String msg) { String[] chars = msg.split(""); String resultString = ""; for (int i = (chars.length - 1); i != 0; i--) { resultString += chars[i]; } return resultString; } }
Comment cela fonctionne ? Au début, quand le client se connecte, le serveur répond avec "> Connected". Le client lit alors ce message et la console affiche le message "Your message :". Quand le client introduit et valide son texte, ce dernier est envoyé au serveur avec output.writeObject(). Le serveur le récupère alors avec in.readObject(). Le serveur transforme le message et renvoie la transformation au serveur. Tant que le message envoyé est différent de "q", la conversation continue.
Thread safety des sockets en Java