Saluti.
Oghje vogliu vede u prucessu di scrittura di l'applicazioni client-server chì eseguisce e funzioni di l'utilità standard di Windows, cum'è Telnet, TFTP, et cetera, et cetera in pura Java. Hè chjaru chì ùn aghju micca purtatu nunda di novu - tutte queste utilità anu travagliatu cù successu per più di un annu, ma crede chì micca tutti sapi ciò chì passa sottu u cappucciu.
Questu hè esattamente ciò chì serà discutitu sottu u cut.
In questu articulu, per ùn trascinà micca, in più di l'infurmazioni generale, scriveraghju solu nantu à u servitore Telnet, ma à u mumentu ci hè ancu materiale nantu à altre utilità - serà in più parti di a serie.
Prima di tuttu, avete bisognu di capisce ciò chì Telnet hè, ciò chì hè necessariu, è ciò chì hè utilizatu. Ùn citeraghju micca e fonti verbatim (se necessariu, aghjustà un ligame à i materiali nantu à u tema à a fine di l'articulu), diceraghju solu chì Telnet furnisce l'accessu remoto à a linea di cummanda di u dispusitivu. In generale, questu hè induve a so funziunalità finisce (aghju deliberatamente tenutu silenziu annantu à l'accessu à u portu di u servitore; più nantu à questu dopu). Questu significa chì per implementà, avemu bisognu di accettà una linea nantu à u cliente, passà à u servitore, pruvate di passà à a linea di cummanda, leghjite a risposta di a linea di cumanda, se ci hè una, passala torna à u cliente è mostrallu nantu à u screnu, o, in casu d'errore, fate à l'utilizatori sapè chì qualcosa hè sbagliatu.
Per implementà u sopra, per quessa, avemu bisognu di classi di travagliu 2 è una classe di teste da quale lanciaremu u servitore è attraversu quale u cliente hà da travaglià.
Dunque, in u mumentu, a struttura di l'applicazione include:
- TelnetClient
- TelnetClientTester
- TelnetServer
- TelnetServerTester
Passemu per ognunu di elli:
TelnetClient
Tuttu sta classa deve esse capace di fà hè di mandà cumandamenti ricevuti è mostra e risposte ricevute. Inoltre, avete bisognu di pudè cunnette à un portu arbitrariu (cum'è chjamatu sopra) di un dispositivu remoto è disconnect da ellu.
Per ottene questu, sò state implementate e seguenti funzioni:
Una funzione chì piglia un indirizzu di socket cum'è argumentu, apre una cunnessione è principia i flussi di input è output (variabili di flussu sò dichjarati sopra, i fonti cumpleti sò à a fine di l'articulu).
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());
}
}
Overloading a stessa funzione, cunnette à u portu predeterminatu - per telnet questu hè 23
public void run(String ip)
{
run(ip, 23);
}
A funzione leghje caratteri da u teclatu è li manda à u socket di output - chì hè tipicu, in modu di linea, micca in modu di caratteri:
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());
}
}
A funzione riceve dati da u socket è mostra nantu à u screnu
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());
}
}
A funzione ferma a ricezione è a trasmissione di dati
public void stop()
{
reader.stop();
writer.stop();
}
}
TelnetServer
Questa classa deve avè a funziunalità di riceve un cumandamentu da un socket, mandendu per l'esekzione, è mandà una risposta da u cumandamentu à u socket. U prugramma deliberatamente ùn cuntrolla micca i dati di input, perchè prima, ancu in "telnet boxed" hè pussibule formate u discu di u servitore, è in segundu, u prublema di sicurità in questu articulu hè omessa in principiu, è per quessa ùn ci hè micca. una parolla nantu à a criptografia o SSL.
Ci hè solu 2 funzioni (una d'elli hè overloaded), è in generale questu ùn hè micca una pratica assai bona, ma per i scopi di questu compitu, mi pareva adattatu per lascià tuttu ciò chì hè.
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();
}
U prugramma apre u portu di u servitore, leghje e dati da ellu finu à chì scontra un caratteru di fine di cumandamentu, passa u cumandamentu à un novu prucessu, è redirige l'output da u prucessu à u socket. Tuttu hè simplice cum'è un fucile d'assaltu Kalashnikov.
Per quessa, ci hè una sovraccarica per sta funzione cù un portu predeterminatu:
public void run()
{
run(23);
}
Eppo, per quessa, a funzione chì ferma u servitore hè ancu triviale, interrompe u ciclu eternu, violendu a so cundizione.
public void stop()
{
System.out.println("Server was stopped");
this.isRunning = false;
}
Ùn daraghju micca classi di teste quì, sò quì sottu - tuttu ciò chì facenu hè di verificà a funziunalità di i metudi publichi. Tuttu hè nantu à u git.
Per sintetizà, in un paru di serate pudete capisce i principii di u funziunamentu di e utilità principali di a consola. Avà, quandu telenet à un computer remoto, capiscenu ciò chì succede - a magia hè sparita)
Allora, i ligami:
Source: www.habr.com