Kirjutamistarkvara Windowsi klient-serveri utiliitide funktsionaalsusega, osa 01

Tervitused.

Täna tahaksin vaadata kliendi-serveri rakenduste kirjutamise protsessi, mis täidavad Windowsi standardsete utiliitide funktsioone, nagu Telnet, TFTP jne jne puhtas Javas. On selge, et ma ei too midagi uut - kõik need kommunaalteenused on edukalt töötanud juba rohkem kui aasta, kuid usun, et kõik ei tea, mis kapoti all toimub.

Just sellest tulebki lõike all juttu.

Selles artiklis, et seda mitte venitada, kirjutan lisaks üldisele teabele ainult Telneti serverist, kuid praegu on materjale ka muude utiliitide kohta - see on seeria edasistes osades.

Kõigepealt peate välja mõtlema, mis on Telnet, milleks seda vaja on ja milleks seda kasutatakse. Ma ei tsiteeri allikaid sõna-sõnalt (vajadusel lisan artikli lõppu lingi teemakohastele materjalidele), ütlen vaid, et Telnet pakub seadme käsureale kaugjuurdepääsu. Üldiselt sellega selle funktsionaalsus lõpeb (serveri pordile juurdepääsust vaikisin meelega; sellest hiljem). See tähendab, et selle rakendamiseks peame aktsepteerima kliendil rea, edastama selle serverile, proovima seda käsureale edastada, lugema käsurea vastuse, kui see on olemas, edastama selle kliendile tagasi ja kuvage see ekraanil või tõrke korral andke kasutajale teada, et midagi on valesti.

Eelneva rakendamiseks vajame vastavalt 2 tööklassi ja mõnda testklassi, millest käivitame serveri ja mille kaudu klient töötab.
Seetõttu sisaldab praegu rakenduse struktuur järgmist:

  • TelnetClient
  • TelnetClientTester
  • Telnetiserver
  • TelnetServerTester

Vaatame igaüks neist läbi:

TelnetClient

Kõik see klass peaks suutma saata vastuvõetud käske ja näidata saadud vastuseid. Lisaks peate saama ühenduse luua kaugseadme suvalise (nagu ülalpool mainitud) pordiga ja sellest lahti ühendada.

Selle saavutamiseks rakendati järgmised funktsioonid:

Funktsioon, mis võtab argumendiks pesa aadressi, avab ühenduse ning käivitab sisend- ja väljundvoo (voo muutujad on deklareeritud ülal, täisallikad on 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, ühenduse loomine vaikepordiga - telneti jaoks on see 23


    public void run(String ip)
    {
        run(ip, 23);
    }

Funktsioon loeb tähemärke klaviatuurilt ja saadab need väljundpesasse – mis on tüüpiline rearežiimis, mitte märgirežiimis:


    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 pesast andmeid vastu ja kuvab need ekraanil


    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 peatab andmete vastuvõtmise ja edastamise


    public void stop()
    {
        reader.stop();
        writer.stop();
    }
}

Telnetiserver

Sellel klassil peab olema funktsioon, et saada käsk pesast, saata see täitmiseks ja saadab käsult vastus tagasi pesasse. Programm ei kontrolli teadlikult sisendandmeid, sest esiteks on isegi “kastiga telnetis” võimalik serveri ketast vormindada ja teiseks on siin artiklis turvalisuse küsimus põhimõtteliselt välja jäetud ja seetõttu pole paar sõna krüptimise või SSL-i kohta.

Funktsioone on ainult 2 (üks neist on ülekoormatud) ja üldiselt pole see väga hea tava, kuid selle ülesande jaoks tundus mulle sobiv jätta kõik nii nagu on.

 boolean isRunning = true;
    public void run(int port)    {

        (new Thread(()->{ try {
            ServerSocket ss = new ServerSocket(port); // создаем сокет сервера и привязываем его к вышеуказанному порту
            System.out.println("Port "+port+" is waiting for connections");

            Socket socket = ss.accept();
            System.out.println("Connected");
            System.out.println();

            // Берем входной и выходной потоки сокета, теперь можем получать и отсылать данные клиенту.
            InputStream sin = socket.getInputStream();
            OutputStream sout = socket.getOutputStream();

            Map<String, String> 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 = "Something gets wrong... Err code: "+ 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("Error: " + e.getMessage());
                    }
                }).start();
                System.out.println(buffer);
                buffer = "";

            }
        }
        catch(Exception x) {
            System.out.println(x.getMessage());
        }})).start();

    }

Programm avab serveri pordi, loeb sealt andmeid, kuni kohtab käsulõpu märki, edastab käsu uuele protsessile ja suunab protsessi väljundi pesasse. Kõik on lihtne nagu Kalašnikovi ründerelv.

Seetõttu on selle funktsiooni jaoks vaikepordiga ülekoormus:

 public void run()
    {
        run(23);
    }

Noh, vastavalt sellele on serverit peatav funktsioon ka triviaalne, see katkestab igavese ahela, rikkudes selle seisukorda.

    public void stop()
    {
        System.out.println("Server was stopped");
        this.isRunning = false;
    }

Ma ei anna siin testklasse, need on allpool - kõik, mida nad teevad, on avalike meetodite funktsionaalsuse kontrollimine. Kõik on paigas.

Kokkuvõtteks võib öelda, et paari õhtuga saate aru peamiste konsooli utiliitide tööpõhimõtetest. Nüüd, kui ühendame televõrgu kaugarvutiga, saame aru, mis toimub - maagia on kadunud)

Niisiis, lingid:
Kõik allikad olid, on ja jäävad siia
Telneti kohta
Lisateavet Telneti kohta

Allikas: www.habr.com

Lisa kommentaar