Skriuwsoftware mei de funksjonaliteit fan Windows-client-server-helpprogramma's, diel 01

Groetnis.

Hjoed wol ik sjen nei it proses fan it skriuwen fan client-server-applikaasjes dy't de funksjes útfiere fan standert Windows-nutsbedriuwen, lykas Telnet, TFTP, ensfh., ensfh. yn suver Java. It is dúdlik dat ik neat nij sil bringe - al dizze nutsbedriuwen wurkje al mear as ien jier mei súkses, mar ik leau dat net elkenien wit wat der ûnder de motorkap bart.

Dit is krekt wat wurdt besprutsen ûnder de besuniging.

Yn dit artikel, om it net te slepen, neist algemiene ynformaasje, sil ik allinich skriuwe oer de Telnet-tsjinner, mar op it stuit is d'r ek materiaal oer oare nutsbedriuwen - it sil wêze yn oare dielen fan 'e searje.

Alderearst moatte jo útfine wat Telnet is, wêrfoar it is en wêrfoar it wurdt brûkt. Ik sil boarnen net ferbatim oanhelje (as it nedich is, sil ik in keppeling taheakje oan materialen oer it ûnderwerp oan 'e ein fan it artikel), ik sil allinich sizze dat Telnet tagong op ôfstân leveret ta de kommandorigel fan it apparaat. Yn it algemien, dit is wêr't syn funksjonaliteit einiget (ik haw bewust stil hâlden oer tagong ta de serverpoarte; dêroer letter mear). Dit betsjut dat om it út te fieren, wy in rigel op 'e kliïnt moatte akseptearje, it oan 'e tsjinner trochjaan, besykje it troch te jaan oan 'e kommandorigel, it antwurd fan 'e kommandorigel lêze, as der is, it weromjaan oan 'e kliïnt en it werjaan op it skerm, of, as flaters, lit de brûker witte dat der wat mis is.

Om it boppesteande út te fieren, hawwe wy dus 2 wurkklassen nedich en wat testklasse wêrfan wy de tsjinner sille lansearje en wêrmei de kliïnt sil wurkje.
Dêrtroch omfettet op it stuit de oanfraachstruktuer:

  • TelnetClient
  • TelnetClientTester
  • TelnetServer
  • TelnetServerTester

Litte wy elk fan har trochgean:

TelnetClient

Al dizze klasse moat wêze kinne om te stjoeren ûntfongen kommando's en lit de ûntfongen antwurden. Derneist moatte jo kinne ferbine mei in willekeurige (lykas hjirboppe neamde) poarte fan in apparaat op ôfstân en dêrmei losmeitsje.

Om dit te berikken, waarden de folgjende funksjes ymplementearre:

In funksje dy't in socketadres as argumint nimt, in ferbining iepenet en ynfier- en útfierstreamen begjint (streamfariabelen wurde hjirboppe ferklearre, folsleine boarnen binne oan 'e ein fan it artikel).

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

Deselde funksje oerladen, ferbine mei de standertpoarte - foar telnet is dit 23


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

De funksje lêst tekens fan it toetseboerd en stjoert se nei de útfier socket - dat is typysk, yn line modus, net karakter modus:


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

De funksje ûntfangt gegevens fan 'e socket en toant it op it skerm


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

De funksje stopt gegevens ûntfangst en oerdracht


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

TelnetServer

Dizze klasse moat de funksjonaliteit hawwe om in kommando te ûntfangen fan in socket, it te stjoeren foar útfiering en in antwurd fan it kommando werom nei de socket te stjoeren. It programma kontrolearret de ynfiergegevens mei opsetsin net, om't earst, sels yn "boxed telnet" it mooglik is om de serverskiif te formatteren, en twad is de kwestje fan feiligens yn dit artikel yn prinsipe weilitten, en dêrom is d'r net in wurd oer fersifering of SSL.

D'r binne mar 2 funksjes (ien fan har is oerladen), en yn 't algemien is dit net in heul goede praktyk, mar foar de doelen fan dizze taak like it my passend om alles te litten sa't it is.

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

    }

It programma iepenet de tsjinner poarte, lêst gegevens fan it oant it tsjinkomt in kommando ein karakter, jout it kommando nei in nij proses, en omliedt de útfier fan it proses nei de socket. Alles is sa ienfâldich as in Kalashnikov assault rifle.

Dêrtroch is d'r in oerlêst foar dizze funksje mei in standertpoarte:

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

No, sadwaande, de funksje dy't stopet de tsjinner is ek triviaal, it ûnderbrekt de ivige lus, yn striid mei syn tastân.

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

Ik sil hjir gjin testklassen jaan, se binne hjirûnder - alles wat se dogge is de funksjonaliteit fan iepenbiere metoaden kontrolearje. Alles is op 'e git.

Om gearfetsje, yn in pear jûnen kinne jo de prinsipes fan wurking fan 'e wichtichste konsole-nutsbedriuwen begripe. No, as wy telenet nei in kompjûter op ôfstân, begripe wy wat der bart - de magy is ferdwûn)

Dus, de keppelings:
Alle boarnen wiene, binne en sille hjir wêze
Oer Telnet
Mear oer Telnet

Boarne: www.habr.com

Add a comment