Rakstīšanas programmatūra ar Windows klienta-servera utilītu funkcionalitāti, 01. daļa

Sveicieni.

Šodien es vēlētos aplūkot klienta-servera lietojumprogrammu rakstīšanas procesu, kas veic standarta Windows utilītu funkcijas, piemēram, Telnet, TFTP utt., utt. tīrā Java. Skaidrs, ka neko jaunu neienesīšu - visas šīs utilītas veiksmīgi darbojas jau vairāk nekā gadu, taču uzskatu, ka ne visi zina, kas notiek zem pārsega.

Tas ir tieši tas, kas tiks apspriests zem griezuma.

Šajā rakstā, lai neievilktos, papildus vispārīgai informācijai rakstīšu tikai par Telnet serveri, bet šobrīd ir arī materiāli par citiem utilītiem - tas būs turpmākajās sērijas daļās.

Pirmkārt, jums ir jāsaprot, kas ir Telnet, kam tas ir vajadzīgs un kam tas tiek izmantots. Avotus necitēšu burtiski (ja nepieciešams, raksta beigās pievienošu saiti uz materiāliem par tēmu), teikšu tikai to, ka Telnet nodrošina attālinātu piekļuvi ierīces komandrindai. Kopumā tā funkcionalitāte beidzas (es apzināti klusēju par piekļuvi servera portam; vairāk par to vēlāk). Tas nozīmē, ka, lai to ieviestu, mums ir jāpieņem klienta rindiņa, jānodod tā serverim, jāmēģina nodot komandrindai, jāizlasa komandrindas atbilde, ja tāda ir, jānodod tā atpakaļ klientam un parādiet to ekrānā vai, ja rodas kļūdas, informējiet lietotāju, ka kaut kas nav kārtībā.

Lai īstenotu augstākminēto, attiecīgi mums ir nepieciešamas 2 darba klases un dažas testa klases, no kurām mēs palaižam serveri un caur kuru strādās klients.
Attiecīgi šobrīd pieteikuma struktūra ietver:

  • TelnetClient
  • TelnetClientTester
  • TelnetServer
  • TelnetServerTester

Apskatīsim katru no tiem:

TelnetClient

Viss, kas šai klasei jāspēj, ir nosūtīt saņemtās komandas un parādīt saņemtās atbildes. Turklāt jums ir jāspēj izveidot savienojumu ar patvaļīgu (kā minēts iepriekš) attālās ierīces portu un atvienoties no tā.

Lai to panāktu, tika ieviestas šādas funkcijas:

Funkcija, kas izmanto ligzdas adresi kā argumentu, atver savienojumu un sāk ievades un izvades straumes (straumes mainīgie ir norādīti iepriekš, pilni avoti ir raksta beigās).

 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());
        }
    }

Pārslogojot to pašu funkciju, izveidojot savienojumu ar noklusējuma portu - telnet tas ir 23


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

Funkcija nolasa rakstzīmes no tastatūras un nosūta tās uz izvades ligzdu — tas ir tipisks rindas režīmā, nevis rakstzīmju režīmā:


    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());
        }
    }

Funkcija saņem datus no ligzdas un parāda tos ekrānā


    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());
        }
    }

Funkcija aptur datu saņemšanu un pārsūtīšanu


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

TelnetServer

Šai klasei ir jābūt tādai, lai saņemtu komandu no ligzdas, nosūtītu to izpildei un nosūtītu atbildi no komandas atpakaļ uz ligzdu. Programma apzināti nepārbauda ievades datus, jo pirmkārt, pat “boxed telnet” ir iespējams formatēt servera disku, otrkārt, drošības jautājums šajā rakstā principā ir izlaists, un tāpēc nav daži vārdi par šifrēšanu vai SSL.

Ir tikai 2 funkcijas (viena no tām ir pārslogota), un kopumā šī nav ļoti laba prakse, bet šī uzdevuma mērķiem man šķita pareizi atstāt visu kā ir.

 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();

    }

Programma atver servera portu, nolasa datus no tā, līdz tiek parādīta komandas beigu rakstzīme, nodod komandu jaunam procesam un novirza izvadi no procesa uz ligzdu. Viss ir tikpat vienkārši kā Kalašņikova triecienšautene.

Attiecīgi šai funkcijai ir pārslodze ar noklusējuma portu:

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

Nu attiecīgi arī funkcija, kas aptur serveri, ir triviāla, tā pārtrauc mūžīgo cilpu, pārkāpjot tā stāvokli.

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

Es šeit nesniegšu pārbaudes nodarbības, tās ir zemāk - viss, ko viņi dara, ir pārbaudīt publisko metožu funkcionalitāti. Viss ir uz vietas.

Rezumējot, pāris vakaros var saprast galveno konsoles utilītu darbības principus. Tagad, kad mēs telenetam uz attālo datoru, mēs saprotam, kas notiek - maģija ir pazudusi)

Tātad, saites:
Visi avoti bija, ir un būs šeit
Par Telnet
Vairāk par Telnet

Avots: www.habr.com

Pievieno komentāru