Windows клиент-сервер утилиталарының функционалдығы бар бағдарламалық жасақтаманы жазу, 01 бөлім

Құттықтау.

Бүгін мен таза Java тілінде Telnet, TFTP және т.б. сияқты стандартты Windows утилиталарының функцияларын орындайтын клиент-сервер қосымшаларын жазу процесін қарастырғым келеді. Мен жаңа ештеңе әкелмейтінім анық - бұл утилиталардың барлығы бір жылдан астам сәтті жұмыс істеп жатыр, бірақ менің ойымша, бәрі капоттың астында не болып жатқанын білмейді.

Бұл дәл осы қысқарту астында талқыланатын болады.

Бұл мақалада оны апарып алмау үшін, жалпы ақпаратқа қоса, мен тек 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

Бұл сыныпта ұяшықтан пәрменді қабылдау, оны орындауға жіберу және командадан розеткаға жауапты жіберу функциясы болуы керек. Бағдарлама енгізілген деректерді әдейі тексермейді, өйткені біріншіден, тіпті «қораптағы 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 туралы толығырақ

Ақпарат көзі: www.habr.com

пікір қалдыру