Salutations.
Aujourd'hui, je voudrais analyser le processus d'écriture d'applications client-serveur qui exécutent les fonctions des utilitaires Windows standard, tels que Telnet, TFTP, et cetera, et cetera en Java pur. Il est clair que je n'apporterai rien de nouveau - tous ces utilitaires fonctionnent avec succès depuis plus d'un an, mais je crois que tout le monde ne sait pas ce qui se passe sous le capot.
C'est ce qui sera discuté sous la coupe.
Dans cet article, afin de ne pas le retarder, en plus des informations générales, je n'écrirai que sur le serveur Telnet, mais pour le moment il y a encore du matériel sur d'autres utilitaires - ce sera dans les autres parties du cycle.
Tout d'abord, vous devez comprendre ce qu'est Telnet, pourquoi il est nécessaire et avec quoi il est mangé. Je ne citerai pas les sources textuellement (si nécessaire, je joindrai un lien vers des documents connexes à la fin de l'article), je peux seulement dire que Telnet fournit un accès à distance à la ligne de commande de l'appareil. Dans l'ensemble, c'est là que s'arrête sa fonctionnalité (j'ai silencieusement contacté le port du serveur en silence, plus en détail plus tard). Donc, pour sa mise en œuvre, nous devons accepter la ligne sur le client, la transférer sur le serveur, essayer de la transférer sur la ligne de commande, lire la réponse de la ligne de commande, le cas échéant, la renvoyer au client et l'afficher, ou, en cas d'occurrence erreurs, faites comprendre à l'utilisateur que quelque chose ne va pas.
Pour implémenter ce qui précède, en conséquence, vous avez besoin de 2 classes de travail et d'une classe de test à partir de laquelle nous allons démarrer le serveur et à travers laquelle le client travaillera.
En conséquence, à l'heure actuelle, la structure de la demande comprend:
- Telnetclient
- TelnetClientTester
- TelnetServer
- TelnetServerTester
Passons en revue chacun d'eux:
TelnetclientTout ce que cette classe devrait pouvoir faire, c'est envoyer les commandes reçues et montrer les réponses reçues. De plus, vous devez pouvoir vous connecter à un port arbitraire (comme mentionné ci-dessus) de l'appareil distant et vous en déconnecter.
Pour cela, les fonctions suivantes ont été implémentées:
Une fonction qui prend une adresse de socket comme argument, ouvre une connexion et démarre les flux d'entrée et de sortie (les variables de flux sont déclarées ci-dessus, sources complètes à la fin de l'article).
public void run(String ip, int port) { try { Socket socket = new Socket(ip, port); InputStream sin = socket.getInputStream(); OutputStream sout = socket.getOutputStream(); Scanner keyboard = new Scanner(System.in); reader = new Thread(()->read(keyboard, sout)); writer = new Thread(()->write(sin)); reader.start(); writer.start(); } catch (Exception e) { System.out.println(e.getMessage()); } }
Surcharge de la même fonction, connexion au port par défaut - pour telnet c'est 23
public void run(String ip) { run(ip, 23); }
La fonction lit les caractères du clavier et les envoie à la prise de sortie - ce qui est typique, dans la chaîne plutôt qu'en mode caractère:
private void read(Scanner keyboard, OutputStream sout) { try { String input = new String(); while (true) { input = keyboard.nextLine(); for (char i : (input + " \n").toCharArray()) sout.write(i); } } catch (Exception e) { System.out.println(e.getMessage()); } }
La fonction reçoit des données de la prise et les affiche à l'écran.
private void write(InputStream sin) { try { int tmp; while (true){ tmp = sin.read(); System.out.print((char)tmp); } } catch (Exception e) { System.out.println(e.getMessage()); } }
La fonction arrête de recevoir et de transmettre des données.
public void stop() { reader.stop(); writer.stop(); } }
TelnetServerCette classe doit avoir la fonctionnalité d'accepter une commande à partir d'un socket, de l'envoyer pour exécution et de renvoyer une réponse de la commande au socket. Le programme ne vérifie pas intentionnellement les données d'entrée, car, d'une part, il est possible de formater le disque du serveur dans la "boîte telnet", et d'autre part, le problème de sécurité dans cet article est omis en principe, et c'est pourquoi il n'y a pas un mot sur le chiffrement ou SSL
Il n'y a que 2 fonctions (dont l'une est surchargée), et en général ce n'est pas une bonne pratique, cependant, dans le cadre de cette tâche, il m'a semblé approprié de tout laisser tel quel.
boolean isRunning = true; public void run(int port) { (new Thread(()->{ try { ServerSocket ss = new ServerSocket(port);
Le programme ouvre le port du serveur, en lit les données jusqu'à ce qu'il rencontre un caractère de fin de commande, transfère la commande vers un nouveau processus et que la sortie du processus soit redirigée vers le socket. Tout est comme un fusil d'assaut Kalachnikov.
En conséquence, pour cette fonction, il y a surcharge avec le port par défaut:
public void run() { run(23); }
Eh bien et en conséquence, la fonction qui arrête le serveur est également banale, elle interrompt le cycle éternel, violant son état.
public void stop() { System.out.println("Server was stopped"); this.isRunning = false; }
Je ne donnerai pas de cours de test ici, ils sont en bas - ils ne font que vérifier les performances des méthodes publiques. Tout est sur la gita.
En résumé, en quelques soirées, vous pouvez comprendre les principes des principaux utilitaires de console. Maintenant, quand nous arrivons à l'ordinateur distant, nous comprenons ce qui se passe - la magie a disparu)
Les liens sont donc:
Toutes les sources étaient, sont et seront iciÀ propos de TelnetEn savoir plus sur Telnet