Skrivprogramvara med funktionerna i Windows klient-serververktyg, del 01

Hälsningar.

Idag skulle jag vilja titta på processen för att skriva klient-serverapplikationer som utför funktionerna i standard Windows-verktyg, såsom Telnet, TFTP, et cetera, et cetera i ren Java. Det är klart att jag inte kommer att ta med något nytt - alla dessa verktyg har fungerat framgångsrikt i mer än ett år, men jag tror att inte alla vet vad som händer under huven.

Detta är precis vad som kommer att diskuteras under snittet.

I den här artikeln, för att inte dra ut det, kommer jag förutom allmän information bara att skriva om Telnet-servern, men för tillfället finns det också material om andra verktyg - det kommer att finnas i ytterligare delar av serien.

Först och främst måste du ta reda på vad Telnet är, vad det behövs för och vad det används till. Jag kommer inte att citera källor ordagrant (om nödvändigt kommer jag att bifoga en länk till material om ämnet i slutet av artikeln), jag kommer bara att säga att Telnet ger fjärråtkomst till enhetens kommandorad. I stort sett är det här dess funktionalitet slutar (jag höll medvetet tyst om att komma åt serverporten; mer om det senare). Detta betyder att för att implementera det måste vi acceptera en rad på klienten, skicka den till servern, försöka skicka den till kommandoraden, läsa kommandoradssvaret, om det finns en, skicka tillbaka den till klienten och visa det på skärmen, eller, om det uppstår fel, låt användaren veta att något är fel.

För att implementera ovanstående behöver vi följaktligen 2 arbetsklasser och någon testklass från vilken vi kommer att starta servern och genom vilken klienten kommer att arbeta.
Följaktligen inkluderar ansökningsstrukturen för närvarande:

  • TelnetClient
  • TelnetClientTester
  • TelnetServer
  • TelnetServerTester

Låt oss gå igenom var och en av dem:

TelnetClient

Allt den här klassen ska kunna göra är att skicka mottagna kommandon och visa de mottagna svaren. Dessutom måste du kunna ansluta till en godtycklig (som nämnts ovan) port på en fjärrenhet och koppla från den.

För att uppnå detta implementerades följande funktioner:

En funktion som tar en socket-adress som ett argument, öppnar en anslutning och startar in- och utströmmar (strömvariabler deklareras ovan, fullständiga källor finns i slutet av artikeln).

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

Överbelasta samma funktion, ansluta till standardporten - för telnet är detta 23


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

Funktionen läser tecken från tangentbordet och skickar dem till utgångsuttaget - vilket är typiskt i linjeläge, inte teckenläge:


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

Funktionen tar emot data från uttaget och visar det på skärmen


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

Funktionen stoppar datamottagning och överföring


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

TelnetServer

Denna klass måste ha funktionen att ta emot ett kommando från en socket, skicka det för exekvering och skicka ett svar från kommandot tillbaka till socket. Programmet kontrollerar inte medvetet indata, för för det första, även i "boxed telnet" är det möjligt att formatera serverdisken, och för det andra utelämnas säkerhetsfrågan i den här artikeln i princip, och det är därför det inte finns ett ord om kryptering eller SSL.

Det finns bara 2 funktioner (en av dem är överbelastad), och i allmänhet är detta inte en särskilt bra praxis, men för denna uppgift verkade det lämpligt för mig att lämna allt som det är.

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

    }

Programmet öppnar serverporten, läser data från den tills det möter ett kommandosluttecken, skickar kommandot till en ny process och omdirigerar utdata från processen till socket. Allt är så enkelt som ett Kalashnikov-gevär.

Följaktligen finns det en överbelastning för denna funktion med en standardport:

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

Tja, följaktligen är funktionen som stoppar servern också trivial, den avbryter den eviga slingan och bryter mot dess tillstånd.

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

Jag kommer inte att ge testklasser här, de är nedan - allt de gör är att kontrollera funktionaliteten hos offentliga metoder. Allt är på git.

För att sammanfatta, på ett par kvällar kan du förstå principerna för driften av huvudkonsolverktygen. Nu, när vi telenetar till en fjärrdator, förstår vi vad som händer - magin har försvunnit)

Så, länkarna:
Alla källor var, är och kommer att finnas här
Om Telnet
Mer om Telnet

Källa: will.com

Lägg en kommentar