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

Бул класс розеткадан буйрукту кабыл алуу, аны аткарууга жөнөтүү жана командадан жоопту кайра розеткага жөнөтүү функциясына ээ болушу керек. Программа киргизген маалыматтарды атайылап текшербейт, анткени биринчиден, ал тургай, "кутуланган телнетте" да сервердик дискти форматтоого болот, экинчиден, бул макалада коопсуздук маселеси принципиалдуу түрдө алынып салынган, ошондуктан бул жерде жок. шифрлөө же 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

Комментарий кошуу