Windows müştəri-server utilitlərinin funksionallığı ilə proqram təminatının yazılması, hissə 01

Salamlar.

Bu gün mən sırf Java-da Telnet, TFTP və s. kimi standart Windows utilitlərinin funksiyalarını yerinə yetirən müştəri-server proqramlarının yazılması prosesinə baxmaq istərdim. Yeni bir şey gətirməyəcəyim aydındır - bütün bu kommunal xidmətlər bir ildən çoxdur uğurla işləyir, amma inanıram ki, başlıq altında nə baş verdiyini hamı bilmir.

Məhz bu kəsim altında müzakirə ediləcək şeydir.

Bu yazıda, onu sürükləməmək üçün, ümumi məlumatdan əlavə, yalnız Telnet serveri haqqında yazacağam, lakin bu anda digər yardım proqramları haqqında da material var - bu, seriyanın sonrakı hissələrində olacaq.

Əvvəlcə Telnetin nə olduğunu, nə üçün lazım olduğunu və nə üçün istifadə edildiyini anlamaq lazımdır. Mənbələrdən sözsüz sitat gətirməyəcəyəm (lazım gələrsə, məqalənin sonunda mövzu ilə bağlı materiallara keçid əlavə edəcəm), yalnız Telnet-in cihazın əmr xəttinə uzaqdan girişi təmin etdiyini söyləyəcəyəm. Ümumiyyətlə, onun funksionallığı burada sona çatır (mən bilərəkdən server portuna daxil olmaq barədə susdum; bu barədə daha sonra). Bu o deməkdir ki, onu həyata keçirmək üçün müştəridə bir sətir qəbul etməli, onu serverə ötürməli, onu komanda xəttinə ötürməyə çalışmalı, əmr xəttinin cavabını oxumalı, əgər varsa, onu yenidən müştəriyə ötürməliyik və onu ekranda göstərin və ya səhv olarsa, istifadəçiyə nəyinsə səhv olduğunu bildirin.

Yuxarıdakıları həyata keçirmək üçün müvafiq olaraq bizə 2 işçi sinfi və serveri işə salacağımız və müştərinin işləyəcəyi bir neçə test sinfi lazımdır.
Müvafiq olaraq, hazırda tətbiq strukturuna aşağıdakılar daxildir:

  • TelnetClient
  • TelnetClientTester
  • TelnetServer
  • TelnetServerTester

Onların hər birini nəzərdən keçirək:

TelnetClient

Bu sinifin edə bildiyi hər şey alınan əmrləri göndərmək və alınan cavabları göstərməkdir. Bundan əlavə, uzaq bir cihazın ixtiyari (yuxarıda qeyd edildiyi kimi) portuna qoşula və ondan ayrıla bilməlisiniz.

Buna nail olmaq üçün aşağıdakı funksiyalar həyata keçirildi:

Arqument kimi rozetka ünvanını götürən, əlaqə açan və giriş və çıxış axınlarını işə salan funksiya (axın dəyişənləri yuxarıda elan olunub, tam mənbələr məqalənin sonundadır).

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

Eyni funksiyanı həddən artıq yükləmək, standart porta qoşulmaq - telnet üçün bu 23-dür


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

Funksiya klaviaturadan simvolları oxuyur və onları çıxış yuvasına göndərir - bu tipikdir, simvol rejimində deyil, xətt rejimində:


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

Funksiya rozetkadan məlumatları qəbul edir və onu ekranda göstərir


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

Funksiya məlumatların qəbulunu və ötürülməsini dayandırır


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

TelnetServer

Bu sinif soketdən əmr almaq, onu icraya göndərmək və komandadan cavabı yenidən rozetkaya göndərmək funksiyasına malik olmalıdır. Proqram qəsdən daxil olan məlumatları yoxlamır, çünki birincisi, hətta “qutulu telnet”də də server diskini formatlaşdırmaq mümkündür, ikincisi, bu məqalədə təhlükəsizlik məsələsi prinsipcə buraxılıb və buna görə də yoxlanılır. şifrələmə və ya SSL haqqında bir söz.

Cəmi 2 funksiya var (onlardan biri həddən artıq yüklənib) və ümumiyyətlə, bu çox yaxşı təcrübə deyil, amma bu tapşırığın məqsədləri üçün hər şeyi olduğu kimi buraxmaq mənə uyğun gəldi.

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

    }

Proqram server portunu açır, komandanın son simvolu ilə qarşılaşana qədər ondan məlumatları oxuyur, əmri yeni prosesə ötürür və çıxışı prosesdən rozetkaya yönləndirir. Hər şey Kalaşnikov avtomatı qədər sadədir.

Müvafiq olaraq, bu funksiya üçün standart portla həddindən artıq yüklənmə var:

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

Yaxşı, buna uyğun olaraq, serveri dayandıran funksiya da əhəmiyyətsizdir, onun vəziyyətini pozaraq əbədi döngəni kəsir.

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

Mən burada test dərsləri verməyəcəyəm, onlar aşağıdadır - onların etdikləri yalnız ictimai metodların funksionallığını yoxlamaqdır. Hər şey git üzərindədir.

Xülasə etmək üçün, bir neçə axşam əsas konsol kommunallarının iş prinsiplərini başa düşə bilərsiniz. İndi uzaq bir kompüterə telenet etdikdə nə baş verdiyini başa düşürük - sehr yox oldu)

Beləliklə, bağlantılar:
Bütün mənbələr burada olub, var və olacaq
Telnet haqqında
Telnet haqqında ətraflı

Mənbə: www.habr.com

Добавить комментарий