Windows istemci-sunucu yardımcı programlarının işlevselliğine sahip yazılım yazma, bölüm 01

Hoşgeldiniz.

Bugün, Telnet, TFTP, vb. gibi standart Windows yardımcı programlarının işlevlerini saf Java ile gerçekleştiren istemci-sunucu uygulamaları yazma sürecine bakmak istiyorum. Yeni bir şey getirmeyeceğim açık - tüm bu araçlar bir yıldan fazla bir süredir başarılı bir şekilde çalışıyor, ancak herkesin kaputun altında neler olup bittiğini bilmediğine inanıyorum.

Kesim altında tartışılacak olan şey tam olarak budur.

Bu yazıda konuyu uzatmamak için genel bilgilere ek olarak sadece Telnet sunucusu hakkında yazacağım ama şu anda diğer yardımcı programlar hakkında da materyal var - serinin ilerleyen bölümlerinde yer alacak.

Öncelikle Telnet'in ne olduğunu, ne için gerekli olduğunu ve ne için kullanıldığını bulmanız gerekiyor. Kaynaklardan birebir alıntı yapmayacağım (gerekirse makalenin sonuna konuyla ilgili materyallere bağlantı ekleyeceğim), sadece Telnet'in cihazın komut satırına uzaktan erişim sağladığını söyleyeceğim. Genel olarak, işlevselliğinin sona erdiği yer burasıdır (Sunucu bağlantı noktasına erişim konusunda kasıtlı olarak sessiz kaldım; buna daha sonra değineceğim). Bu, bunu uygulamak için istemcideki bir satırı kabul etmemiz, onu sunucuya aktarmamız, komut satırına aktarmayı denememiz, komut satırı yanıtını okumamız, varsa istemciye geri aktarmamız ve bunu ekranda görüntüleyin veya hata varsa kullanıcıya bir şeylerin yanlış olduğunu bildirin.

Buna göre yukarıdakileri uygulamak için 2 çalışma sınıfına ve sunucuyu başlatacağımız ve istemcinin çalışacağı bir test sınıfına ihtiyacımız var.
Buna göre şu anda başvuru yapısı şunları içermektedir:

  • Telnet İstemcisi
  • TelnetİstemciTest Cihazı
  • Telnet Sunucusu
  • TelnetSunucuTest Cihazı

Her birinin üzerinden geçelim:

Telnet İstemcisi

Bu sınıfın tek yapması gereken, alınan komutları göndermek ve alınan yanıtları göstermektir. Ek olarak, uzak bir cihazın isteğe bağlı (yukarıda belirtildiği gibi) bağlantı noktasına bağlanabilmeniz ve bağlantısını kesebilmeniz gerekir.

Bunu başarmak için aşağıdaki işlevler uygulandı:

Argüman olarak soket adresini alan, bir bağlantı açan ve giriş ve çıkış akışlarını başlatan bir işlev (akış değişkenleri yukarıda açıklanmıştır, tüm kaynaklar makalenin sonundadır).

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

Aynı işlevin aşırı yüklenmesi, varsayılan bağlantı noktasına bağlanma - telnet için bu 23'tür


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

İşlev, klavyedeki karakterleri okur ve bunları çıkış soketine gönderir; bu, karakter modunda değil, satır modunda tipiktir:


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

Fonksiyon, soketten veri alır ve ekranda görüntüler.


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

Fonksiyon veri alımını ve iletimini durdurur


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

Telnet Sunucusu

Bu sınıf, bir soketten komut alma, onu yürütmeye gönderme ve komuttan gelen yanıtı tekrar sokete gönderme işlevine sahip olmalıdır. Program kasıtlı olarak giriş verilerini kontrol etmez, çünkü birincisi, “kutulu telnet”te bile sunucu diskini biçimlendirmek mümkündür ve ikinci olarak, bu makalede güvenlik konusu prensipte atlanmıştır ve bu nedenle yoktur. şifreleme veya SSL hakkında birkaç kelime.

Yalnızca 2 işlev var (bunlardan biri aşırı yüklenmiş) ve genel olarak bu pek iyi bir uygulama değil, ancak bu görevin amaçları açısından her şeyi olduğu gibi bırakmak bana uygun göründü.

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

    }

Program sunucu portunu açar, bir komut bitiş karakteriyle karşılaşıncaya kadar buradan veri okur, komutu yeni bir prosese iletir ve prosesin çıktısını sokete yönlendirir. Her şey Kalaşnikof saldırı tüfeği kadar basit.

Buna göre, bu işlev için varsayılan bağlantı noktasıyla aşırı yük vardır:

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

Buna göre, sunucuyu durduran işlev de önemsizdir, sonsuz döngüyü kesintiye uğratarak durumunu ihlal eder.

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

Burada test dersleri vermeyeceğim, aşağıdalar - tek yaptıkları genel yöntemlerin işlevselliğini kontrol etmektir. Her şey git'te.

Özetlemek gerekirse, birkaç akşamda ana konsol yardımcı programlarının çalışma prensiplerini anlayabilirsiniz. Artık uzaktaki bir bilgisayara telenet yaptığımızda ne olduğunu anlıyoruz - sihir ortadan kalktı)

Yani, bağlantılar:
Tüm kaynaklar buradaydı, burada ve olacak
Telnet Hakkında
Telnet'le ilgili daha fazla bilgi

Kaynak: habr.com

Yorum ekle