Windows հաճախորդ-սերվերի կոմունալ ծրագրերի ֆունկցիոնալությամբ գրելու ծրագրակազմ, մաս 01

Ողջույններ:

Այսօր ես կցանկանայի դիտարկել հաճախորդ-սերվեր հավելվածներ գրելու գործընթացը, որոնք կատարում են Windows-ի ստանդարտ կոմունալ ծրագրերի գործառույթները, ինչպիսիք են Telnet, TFTP և այլն, և այլն մաքուր Java-ում: Հասկանալի է, որ ես ոչ մի նոր բան չեմ բերի. այս բոլոր կոմունալ ծառայությունները հաջողությամբ աշխատում են ավելի քան մեկ տարի, բայց ես հավատում եմ, որ ոչ բոլորը գիտեն, թե ինչ է կատարվում գլխարկի տակ:

Հենց սա էլ կքննարկվի կտրվածքի տակ։

Այս հոդվածում, որպեսզի այն չձգձգվի, բացի ընդհանուր տեղեկություններից, ես կգրեմ միայն Telnet սերվերի մասին, բայց այս պահին նյութեր կան նաև այլ կոմունալ ծառայությունների մասին. այն կլինի շարքի հետագա մասերում:

Նախ պետք է պարզել, թե ինչ է Telnet-ը, ինչի համար է այն անհրաժեշտ և ինչի համար է այն օգտագործվում: Աղբյուրները բառացի չեմ մեջբերի (անհրաժեշտության դեպքում հոդվածի վերջում կկցեմ թեմայի վերաբերյալ նյութերի հղումը), միայն կասեմ, որ Telnet-ը հեռահար մուտք է ապահովում սարքի հրամանի տող: Մեծ հաշվով, այստեղ ավարտվում է նրա ֆունկցիոնալությունը (ես միտումնավոր լռում էի սերվերի պորտին մուտք գործելու մասին, դրա մասին ավելի ուշ): Սա նշանակում է, որ այն իրականացնելու համար մենք պետք է ընդունենք մի տող հաճախորդի վրա, փոխանցենք այն սերվերին, փորձենք փոխանցել այն հրամանի տողին, կարդալ հրամանի տողի պատասխանը, եթե այդպիսին կա, այն հետ փոխանցենք հաճախորդին և ցուցադրել այն էկրանին կամ, եթե սխալներ կան, օգտագործողին տեղեկացրեք, որ ինչ-որ բան այն չէ:

Վերոնշյալն իրականացնելու համար, համապատասխանաբար, մեզ անհրաժեշտ է 2 աշխատանքային դաս և ինչ-որ թեստային դաս, որտեղից մենք կգործարկենք սերվերը և որի միջոցով կաշխատի հաճախորդը։
Ըստ այդմ, այս պահին հայտի կառուցվածքը ներառում է.

  • TelnetClient
  • TelnetClientTester
  • TelnetServer
  • TelnetServerTester

Եկեք անցնենք դրանցից յուրաքանչյուրի միջով.

TelnetClient

Այն ամենը, ինչ այս դասը պետք է կարողանա անել՝ ուղարկել ստացված հրամանները և ցույց տալ ստացված պատասխանները: Բացի այդ, դուք պետք է կարողանաք միանալ հեռավոր սարքի կամայական (ինչպես նշվեց վերևում) պորտին և անջատվել դրանից:

Դրան հասնելու համար իրականացվել են հետևյալ գործառույթները.

Գործառույթ, որը ընդունում է վարդակից հասցեն որպես արգումենտ, բացում է կապը և սկսում մուտքային և ելքային հոսքեր (հոսքի փոփոխականները հայտարարված են վերևում, ամբողջական աղբյուրները՝ հոդվածի վերջում)։

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

Նույն գործառույթի գերբեռնում, լռելյայն պորտին միանալը - telnet-ի համար սա 23 է


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

Ֆունկցիան կարդում է նիշերը ստեղնաշարից և ուղարկում դրանք ելքային վարդակից, ինչը բնորոշ է գծային ռեժիմում, ոչ թե նիշերի ռեժիմում:


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

Ֆունկցիան տվյալներ է ստանում վարդակից և ցուցադրում այն ​​էկրանին


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

Գործառույթը դադարեցնում է տվյալների ընդունումը և փոխանցումը


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

TelnetServer

Այս դասը պետք է ունենա վարդակից հրաման ստանալու, այն կատարման ուղարկելու և հրամանից պատասխանը հետ վարդակից ուղարկելու գործառույթ: Ծրագիրը միտումնավոր չի ստուգում մուտքային տվյալները, քանի որ նախ, նույնիսկ «boxed telnet»-ում հնարավոր է ֆորմատավորել սերվերի սկավառակը, և երկրորդ՝ այս հոդվածում անվտանգության հարցը սկզբունքորեն բաց է թողնված, և այդ պատճառով չկա. մի քանի խոսք կոդավորման կամ SSL-ի մասին:

Կա ընդամենը 2 գործառույթ (դրանցից մեկը գերբեռնված է), և ընդհանուր առմամբ դա այնքան էլ լավ պրակտիկա չէ, բայց այս առաջադրանքի նպատակների համար ինձ տեղին թվաց ամեն ինչ թողնել այնպես, ինչպես կա։

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

    }

Ծրագիրը բացում է սերվերի նավահանգիստը, կարդում է դրանից տվյալները, մինչև որ հանդիպի հրամանի ավարտի նիշին, հրամանը փոխանցում է նոր գործընթացի և ելքը պրոցեսից վերահղում դեպի վարդակից: Ամեն ինչ պարզ է, ինչպես Կալաշնիկով ինքնաձիգը։

Համապատասխանաբար, այս ֆունկցիայի համար գերբեռնվածություն կա լռելյայն պորտով.

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

Դե, համապատասխանաբար, սերվերը կանգնեցնող գործառույթը նույնպես տրիվիալ է, այն ընդհատում է հավերժական օղակը՝ խախտելով դրա վիճակը։

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

Ես այստեղ թեստային դասեր չեմ տա, դրանք ներքևում են, այն ամենը, ինչ նրանք անում են, ստուգում են հանրային մեթոդների ֆունկցիոնալությունը: Ամեն ինչ պատրաստ է:

Ամփոփելու համար, մի քանի երեկոների ընթացքում դուք կարող եք հասկանալ հիմնական վահանակի կոմունալ ծառայությունների շահագործման սկզբունքները: Այժմ, երբ մենք հեռահաղորդակցում ենք հեռավոր համակարգչին, հասկանում ենք, թե ինչ է կատարվում. կախարդանքն անհետացել է)

Այսպիսով, հղումները.
Բոլոր աղբյուրները եղել են, կան և կլինեն այստեղ
Telnet-ի մասին
Ավելին Telnet-ի մասին

Source: www.habr.com

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