Tere.
Täna tahaksime arutada kliendi-serveri rakenduste kirjutamise protsessi, mis täidavad Windowsi standardsete utiliitide funktsioone nagu Telnet, TFTP jne, puhtas Javaski. On selge, et ma ei too midagi uut — kõik need utiliidid on juba aastaid edukalt töötanud, kuid arvan, et mitte kõik ei tea, mis nende taga toimub.
Just sellest juttu tuleb.
Selles artiklis, et mitte seda venitada, kirjutan ma ainult Telnet serverist, kuid hetkel on ka teisi utiliite, mille kohta on materjali — need tulevad hiljem sarja järgmistes osades.
Esiteks, tuleks aru saada, mis on Telnet, milleks seda vaja on ja kuidas sellega ümber käia. Ma ei hakka allikaid sõna-sõnalt tsiteerima (kui vaja — lisatakse artikli lõpus lingid teemale), ütlen vaid, et Telnet võimaldab kaugjuurdepääsu seadme käsureale. Suures osas sellega tema funktsionaalsus lõpeb (serveri pordi juurde pääsemisest ma praegu ei räägi, sellest hiljem). Seega, selle rakendamiseks peame klientide kaudu võtma andmearmu, edastama selle serverisse, proovima seda käsureale edastada, lugema käsurea vastuse, kui see on olemas, edastama selle tagasi kliendile ja kuvama ekraanile või, kui tekib viga, teavitama kasutajat, et midagi on valesti.
Selleks on vastavalt vaja kahte töötavat klassi ja ühte testimis klassi, mille kaudu me serverit käivitame ja mille kaudu klient töötab.
Seega praeguse seisuga sisaldab rakenduse struktuur:
- TelnetClient
- TelnetClientTester
- TelnetServer
- TelnetServerTester
Vaatame igaüht neist lähemalt:
TelnetClient
Kõik, mida see klass peaks oskama teha — edastada saadud käske ja näidata saadud vastuseid. Lisaks peab olema võimalik ühendada vägisi (nagu mainitud) kaugseadme pordiga ja sellest lahti ühenduda.
Selleks on rakendatud järgmised funktsioonid:
Funktsioon, mis võtab argumendiks pordi aadressi, avab ühenduse ja käivitab sisendi ja väljundi voogude (voo muutujad on määratud eespool, täielikud lähtekoodid — artikli lõpus).
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());
}
}
Sama funktsiooni ülekoormamine, mis ühendub vaikimisi pordiga — telnet jaoks on see 23
public void run(String ip)
{
run(ip, 23);
}
Funktsioon loeb klaviatuurilt märke ja saadab need väljundpessa — nagu tavaks, reamoodulisse, mitte tähemärkimoodulisse:
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());
}
}
Funktsioon võtab andmeid soketist ja kuvab need ekraanile
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());
}
}
Funktsioon lõpetab andmete vastuvõtmise ja edastamise
public void stop()
{
reader.stop();
writer.stop();
}
}TelnetServer
See klass peaks olema võimeline võtma käske soketist, saatma need täitmiseks ja edastama vastuse käsust tagasi soketisse. Programmis ei ole teadlikult sissekandeid kontrollimist, kuna esiteks on 'karbitelevisioonis' võimalik ketast formaadida ning teiseks, turvaküsimust ei käsitleta selles artiklis üldse ja seetõttu ei ole siin ühtegi sõna krüpteerimise või SSL-i kohta.
Siin on ainult 2 funktsiooni (üks neist on ülekoormatud), ja see ei ole üldiselt hea praktika, kuid antud ülesande raames tundus mõistlik jätta kõik nii nagu on.
boolean isRunning = true;
public void run(int port) {
(new Thread(()->{ try {
ServerSocket ss = new ServerSocket(port); // loome serveri soketi ja seome selle ülaltoodud sadamaga
System.out.println("Port " + port + " on ootamas ühendusi");
Socket socket = ss.accept();
System.out.println("Ühendatud");
System.out.println();
// Saame sissetulevad ja väljaminevad soketi vood, nüüd saame klientidele andmeid edastada.
InputStream sin = socket.getInputStream();
OutputStream sout = socket.getOutputStream();
Map env = System.getenv();
String wayToTemp = env.get("TEMP") + "tmp.txt";
for (int i : ("Connectednnr".toCharArray()))
sout.write(i);
sout.flush();
String buffer = new String();
while (isRunning) {
int intReader = 0;
while ((char) intReader != 'n') {
intReader = sin.read();
buffer += (char) intReader;
}
final String inputToSubThread = "cmd /c " + buffer.substring(0, buffer.length() - 2) + " 2>&1";
new Thread(() -> {
try {
Process p = Runtime.getRuntime().exec(inputToSubThread);
InputStream out = p.getInputStream();
Scanner fromProcess = new Scanner(out);
try {
while (fromProcess.hasNextLine()) {
String temp = fromProcess.nextLine();
System.out.println(temp);
for (char i : temp.toCharArray())
sout.write(i);
sout.write('n');
sout.write('r');
}
}
catch (Exception e) {
String output = "Midagi läks valesti... Viga kood: " + e.getStackTrace();
System.out.println(output);
for (char i : output.toCharArray())
sout.write(i);
sout.write('n');
sout.write('r');
}
p.getErrorStream().close();
p.getOutputStream().close();
p.getInputStream().close();
sout.flush();
}
catch (Exception e) {
System.out.println("Viga: " + e.getMessage());
}
}).start();
System.out.println(buffer);
buffer = "";
}
}
catch(Exception x) {
System.out.println(x.getMessage());
}})).start();
}
Programm avab serveri porta, loeb andmeid, kuni jõuab käsu lõpetamise sümbolini, edastab käsu uude protsessi ja selle väljund suunatakse soketti. Kõik on sama lihtne nagu Kalašnikovi automaat.
Seega on selle funktsiooni jaoks olemas ülekload vaikeportiga:
public void run()
{
run(23);
}Ja seega on ka serveri peatamise funktsioon - kõik on samuti triviaalne, see katkestab igavese tsükli, rikkudes selle tingimust.
public void stop()
{
System.out.println("Server was stopped");
this.isRunning = false;
}Ma ei hakka siin näitama testklasse, need on all — kõik, mida nad teevad, on kontrollida avalike meetodite töövõimet. Kõik on Gitis.
Kokkuvõtteks, paaril õhtul on võimalik mõista peamiste konsoolikasutustest tulenevaid põhimõtteid. Nüüd, kui meil on telnet koos kaugolekuga, mõistame, mis toimub — maagia on kadunud)
Nii et, lingid:
Allikas: habr.com
