Приветствую
วันนี้ฉันอยากจะดูกระบวนการเขียนแอปพลิเคชันไคลเอนต์-เซิร์ฟเวอร์ที่ทำหน้าที่ของยูทิลิตี้ Windows มาตรฐาน เช่น Telnet, TFTP และอื่นๆ อีกมากมายใน Java ล้วนๆ เห็นได้ชัดว่าฉันจะไม่นำสิ่งใหม่ๆ มาใช้ - ยูทิลิตี้ทั้งหมดนี้ทำงานได้สำเร็จมานานกว่าหนึ่งปี แต่ฉันเชื่อว่าไม่ใช่ทุกคนที่รู้ว่าเกิดอะไรขึ้นภายใต้ประทุน
นี่คือสิ่งที่จะมีการหารือภายใต้การตัด
ในบทความนี้เพื่อไม่ให้ลากออกไปนอกเหนือจากข้อมูลทั่วไปฉันจะเขียนเกี่ยวกับเซิร์ฟเวอร์ Telnet เท่านั้น แต่ในขณะนี้ยังมีเนื้อหาเกี่ยวกับยูทิลิตี้อื่น ๆ ด้วย - มันจะอยู่ในส่วนต่อไปของซีรีส์
ก่อนอื่น คุณต้องเข้าใจว่า Telnet คืออะไร จำเป็นสำหรับอะไร และใช้ทำอะไร ฉันจะไม่อ้างอิงแหล่งที่มาทุกคำ (หากจำเป็นฉันจะแนบลิงก์ไปยังเนื้อหาในหัวข้อท้ายบทความ) ฉันจะบอกว่า Telnet ให้การเข้าถึงบรรทัดคำสั่งของอุปกรณ์จากระยะไกลเท่านั้น โดยทั่วไปแล้ว นี่คือจุดที่ฟังก์ชันการทำงานของมันสิ้นสุดลง (ฉันจงใจเงียบเกี่ยวกับการเข้าถึงพอร์ตเซิร์ฟเวอร์ และจะมีข้อมูลเพิ่มเติมในภายหลัง) ซึ่งหมายความว่าในการนำไปใช้งาน เราจำเป็นต้องยอมรับบรรทัดบนไคลเอ็นต์ ส่งต่อไปยังเซิร์ฟเวอร์ พยายามส่งต่อไปยังบรรทัดคำสั่ง อ่านการตอบสนองของบรรทัดคำสั่ง ถ้ามี ให้ส่งต่อไปยังไคลเอ็นต์ และ แสดงบนหน้าจอ หรือหากเกิดข้อผิดพลาด ให้แจ้งให้ผู้ใช้ทราบว่ามีบางอย่างผิดปกติ
เพื่อดำเนินการตามข้างต้น เราจำเป็นต้องมีคลาสการทำงาน 2 คลาสและคลาสทดสอบบางคลาสซึ่งเราจะเปิดใช้เซิร์ฟเวอร์และไคลเอ็นต์จะทำงานผ่านนั้น
ดังนั้น ในขณะนี้ โครงสร้างการสมัคร รวมถึง:
- Telnetไคลเอนต์
- TelnetClientTester
- TelnetServer
- TelnetServerTester
มาดูแต่ละเรื่องกัน:
Telnetไคลเอนต์
คลาสทั้งหมดนี้ควรทำได้คือส่งคำสั่งที่ได้รับและแสดงการตอบกลับที่ได้รับ นอกจากนี้ คุณจะต้องสามารถเชื่อมต่อกับพอร์ตใดก็ได้ (ตามที่กล่าวไว้ข้างต้น) ของอุปกรณ์ระยะไกลและตัดการเชื่อมต่อจากอุปกรณ์นั้น
เพื่อให้บรรลุเป้าหมายนี้ จึงมีการนำฟังก์ชันต่อไปนี้ไปใช้:
ฟังก์ชันที่ใช้ที่อยู่ซ็อกเก็ตเป็นอาร์กิวเมนต์ เปิดการเชื่อมต่อและเริ่มสตรีมอินพุตและเอาต์พุต (ตัวแปรสตรีมได้รับการประกาศไว้ด้านบน แหล่งที่มาทั้งหมดอยู่ที่ส่วนท้ายของบทความ)
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
คลาสนี้ต้องมีฟังก์ชันการรับคำสั่งจากซ็อกเก็ต ส่งเพื่อดำเนินการ และส่งการตอบสนองจากคำสั่งกลับไปยังซ็อกเก็ต โปรแกรมจงใจไม่ตรวจสอบข้อมูลอินพุตเพราะประการแรกแม้ใน "เทลเน็ตแบบบรรจุกล่อง" ก็เป็นไปได้ที่จะฟอร์แมตดิสก์เซิร์ฟเวอร์และประการที่สองประเด็นด้านความปลอดภัยในบทความนี้ถูกละเว้นในหลักการและนั่นคือสาเหตุที่ไม่มี คำเกี่ยวกับการเข้ารหัสหรือ 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();
}
โปรแกรมจะเปิดพอร์ตเซิร์ฟเวอร์ อ่านข้อมูลจนกระทั่งพบอักขระสิ้นสุดคำสั่ง ส่งคำสั่งไปยังกระบวนการใหม่ และเปลี่ยนเส้นทางเอาต์พุตจากกระบวนการไปยังซ็อกเก็ต ทุกอย่างง่ายดายเหมือนปืนไรเฟิลจู่โจม Kalashnikov
ดังนั้นจึงมีการโอเวอร์โหลดสำหรับฟังก์ชันนี้ด้วยพอร์ตเริ่มต้น:
public void run()
{
run(23);
}
ดังนั้นฟังก์ชั่นที่หยุดเซิร์ฟเวอร์จึงเป็นเรื่องเล็กน้อยเช่นกันมันขัดจังหวะการวนซ้ำชั่วนิรันดร์โดยละเมิดเงื่อนไขของมัน
public void stop()
{
System.out.println("Server was stopped");
this.isRunning = false;
}
ฉันจะไม่จัดชั้นเรียนทดสอบที่นี่ ชั้นเรียนอยู่ด้านล่าง - สิ่งที่พวกเขาทำคือตรวจสอบการทำงานของวิธีการสาธารณะ ทุกอย่างอยู่ที่คอมไพล์
โดยสรุปในช่วงเย็นคุณสามารถเข้าใจหลักการทำงานของยูทิลิตี้คอนโซลหลักได้ ตอนนี้เมื่อเราเทเลเน็ตไปยังคอมพิวเตอร์ระยะไกล เราเข้าใจสิ่งที่เกิดขึ้น - ความมหัศจรรย์ได้หายไป)
ดังนั้นลิงค์:
ที่มา: will.com