نرم افزار رایتینگ با قابلیت های سرویس گیرنده-سرور ویندوز قسمت 01

Приветствую

امروز می‌خواهم به روند نوشتن برنامه‌های سرویس گیرنده-سرور که عملکردهای ابزارهای استاندارد ویندوز، مانند Telnet، TFTP، و غیره را در جاوا خالص انجام می‌دهند، نگاهی بیاندازم. واضح است که من چیز جدیدی نمی‌آورم - همه این ابزارها بیش از یک سال است که با موفقیت کار می‌کنند، اما معتقدم همه نمی‌دانند که در زیر کاپوت چه می‌گذرد.

این دقیقاً همان چیزی است که در زیر برش مورد بحث قرار خواهد گرفت.

در این مقاله، برای اینکه آن را طولانی نکنم، علاوه بر اطلاعات کلی، فقط در مورد سرور 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

اضافه کردن نظر