كتابة البرامج مع وظائف الأدوات المساعدة لخادم العميل ، الجزء 01

تحية.

أود اليوم تحليل عملية كتابة تطبيقات خادم العميل التي تقوم بوظائف أدوات Windows القياسية ، مثل Telnet و TFTP و et cetera و et cetera في Java البحتة. من الواضح أنني لن أحمل شيئًا جديدًا - كل هذه الأدوات تعمل بنجاح منذ أكثر من عام ، لكنني أعتقد أنه ليس كل شخص يعرف ما يحدث تحت الغطاء.

هذا هو ما سيتم مناقشته تحت الخفض.

في هذه المقالة ، حتى لا يتم تأخيرها ، بالإضافة إلى المعلومات العامة ، سأكتب فقط عن خادم Telnet ، ولكن في الوقت الحالي لا تزال هناك مواد على أدوات مساعدة أخرى - ستكون في الأجزاء الأخرى من الدورة.

بادئ ذي بدء ، يجب أن تفهم ما هو Telnet ، ولماذا هناك حاجة إليه وما الذي يتم تناوله به. لن أقتبس من مصادر حرفيًا (إذا لزم الأمر - في نهاية المقال ، سأرفق رابطًا للمواد ذات الصلة) ، يمكنني فقط أن أقول إن Telnet يوفر الوصول عن بُعد إلى سطر أوامر الجهاز. إلى حد كبير ، هذا هو المكان الذي تنتهي فيه وظائفه (لقد اتصلت بصمت بمنفذ الخادم بوعي ، وأكثر حول ذلك لاحقًا). لذلك ، من أجل تنفيذه ، نحتاج إلى قبول السطر الموجود على العميل ، ونقله إلى الخادم ، ومحاولة نقله إلى سطر الأوامر ، وقراءة استجابة سطر الأوامر ، إن وجدت ، ونقله مرة أخرى إلى العميل وعرضه ، أو ، في حالة حدوثه الأخطاء ، وجعل المستخدم يفهم أن هناك شيئا خطأ.

لتنفيذ ما سبق ، بناءً على ذلك ، فأنت بحاجة إلى فئتين عاملتين ، وفئة اختبار نبدأ من خلالها الخادم ومن خلاله سيعمل العميل.
وفقًا لذلك ، في الوقت الحالي ، يتضمن هيكل التطبيق:

  • 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

يجب أن يكون لدى هذه الفئة وظيفة قبول أمر من مأخذ توصيل وإرساله للتنفيذ وإرسال استجابة من الأمر إلى مأخذ التوصيل. لا يقوم البرنامج بالتحقق من بيانات الإدخال عن قصد ، لأنه أولاً ، هناك فرصة لتهيئة قرص الخادم في "box telnet" ، وثانياً ، يتم حذف مشكلة الأمان في هذه المقالة من حيث المبدأ ، ولهذا السبب لا توجد كلمة حول التشفير أو SSL.

لا يوجد سوى وظيفتين (واحدة منها مثقلة بالأعباء) ، وبشكل عام هذه ليست ممارسة جيدة ، ولكن كجزء من هذه المهمة ، بدا لي من المناسب ترك كل شيء كما هو.

  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 :("Connected\n\n\r".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

Source: https://habr.com/ru/post/ar460569/


All Articles