Përshëndetje.
Sot dysh, do tĂ« flasim pĂ«r procesin e shkruarjes sĂ« aplikacioneve klient-server qĂ« kryejnĂ« funksionet e utiliteteve standarde tĂ« Windows, si Telnet, TFTP, etj., etj., nĂ« JavĂ«n e pastĂ«r. ĂshtĂ« e qartĂ« se nuk do tĂ« sjell asgjĂ« tĂ« re â tĂ« gjitha kĂ«to utilitete tashmĂ« funksionojnĂ« me sukses pĂ«r njĂ« kohĂ« tĂ« gjatĂ«, por, besoj se nuk tĂ« gjithĂ« e dinĂ« se çfarĂ« ndodh nĂ«n kapakĂ«t e tyre.
Sikurse flitet për këtë në vazhdim.
NĂ« kĂ«tĂ« artikull, pĂ«r tĂ« mos e çekur, pĂ«rveç informacionit tĂ« pĂ«rgjithshĂ«m, do tĂ« shkruaj vetĂ«m pĂ«r serverin Telnet, por aktualisht ka edhe materiale pĂ«r utilitete tĂ« tjera â ato do tĂ« jenĂ« nĂ« pjesĂ«t e ardhshme tĂ« ciklit.
SĂ« pari, duhet tĂ« kuptojmĂ« se çfarĂ« Ă«shtĂ« Telnet, pĂ«r çfarĂ« Ă«shtĂ« i nevojshĂ«m dhe si e pĂ«rdorim. Nuk do tĂ« citoj fjalĂ« pĂ«r fjalĂ« burimet (nĂ«se Ă«shtĂ« e nevojshme â nĂ« fund tĂ« artikullit do tĂ« bashkĂ«ngjitet njĂ« lidhje pĂ«r materialet mbi temĂ«n), do tĂ« them vetĂ«m se Telnet siguron akses tĂ« largĂ«t nĂ« komandĂ«n e pajisjes. NĂ« thelb, kĂ«tu pĂ«rfundon funksionaliteti i tij (pĂ«r pĂ«rdorimin e portit tĂ« serverit do tĂ« mbaj nĂ« heshtje pĂ«r momentin, pĂ«r kĂ«tĂ« mĂ« vonĂ«). KĂ«shtu qĂ«, pĂ«r zbatimin e tij, na nevojitet tĂ« pranojmĂ« njĂ« varg nĂ« klient, ta transferojmĂ« atĂ« nĂ« server, tĂ« pĂ«rpiqemi ta dĂ«rgojmĂ« nĂ« komandĂ«n tuaj, tĂ« marrim pĂ«rgjigjen e komandĂ«s, nĂ«se ka, ta transferojmĂ« pĂ«rsĂ«ri nĂ« klient dhe ta shfaqim nĂ« ekran, ose, nĂ« rast tĂ« ndonjĂ« gabimi, t'i bĂ«jmĂ« tĂ« qartĂ« pĂ«rdoruesit se diçka nuk shkon.
Për realizimin e të përmendurve më sipër, nevojiten përkatësisht 2 klasa funksionale dhe një klasë testuese, nga e cila do të fillojmë serverin dhe përmes së cilës do të punojmë me klientin.
Përkatësisht, struktura aktuale e aplikacionit përfshin:
- TelnetClient
- TelnetClientTester
- TelnetServer
- TelnetServerTester
Do të kalojmë nëpër secilën prej tyre:
TelnetClient
E gjitha çfarĂ« duhet tĂ« jetĂ« nĂ« gjendje tĂ« bĂ«jĂ« kjo klasĂ« â tĂ« dĂ«rgojĂ« komandat e marra dhe tĂ« tregojĂ« pĂ«rgjigjet e marra. PĂ«r mĂ« tepĂ«r, duhet tĂ« jetĂ« nĂ« gjendje tĂ« lidhĂ« me njĂ« port tĂ« rastĂ«sishĂ«m (siç e thashĂ« mĂ« sipĂ«r) tĂ« pajisjes sĂ« largĂ«t dhe tĂ« shkĂ«putet prej tij.
Për këtë janë realizuar funksionet e mëposhtme:
NjĂ« funksion qĂ« pranon si argument adresĂ«n e socket-it, hap lidhjen dhe aktivizon rrjedhat e hyrjes dhe daljes (variablat e rrjedhĂ«s janĂ« shpallur mĂ« sipĂ«r, kodet e plota â nĂ« fund tĂ« artikullit).
publik void run(String ip, int port)
{
përpiqem {
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();
}
kapur (Përjashtim e) {
System.out.println(e.getMessage());
}
}
Overload i kĂ«saj funksioni, qĂ« lidhet me portin e paracaktuar â pĂ«r telnetin Ă«shtĂ« 23
publik void run(String ip)
{
run(ip, 23);
}
Funksioni lexon karakteret nga tastiera dhe i dĂ«rgon nĂ« soketin e daljes â siç Ă«shtĂ« tipike, nĂ« modin e linjĂ«s, dhe jo nĂ« modin e karaktereve:
private void read(Scanner keyboard, OutputStream sout)
{
përpiqem {
String input = new String();
ndërsa (e vërtetë) {
input = keyboard.nextLine();
për (char i : (input + " n").toCharArray())
sout.write(i);
}
}
kapur (Përjashtim e) {
System.out.println(e.getMessage());
}
}
Funksioni merr të dhëna nga soketi dhe i shfaq ato në ekran
private void write(InputStream sin)
{
përpiqem {
int tmp;
ndërsa (e vërtetë){
tmp = sin.read();
System.out.print((char)tmp);
}
}
kapur (Përjashtim e) {
System.out.println(e.getMessage());
}
}
Funksioni ndalon marrjen dhe dërgimin e të dhënave
publik void stop()
{
reader.stop();
writer.stop();
}
}TelnetServer
Ky klas duhet të ketë funksionalitetin e pranimit të komandës nga soketi, dërgimin e saj për egzekutim dhe dërgimin e përgjigjes nga komanda përsëri në soket. Në program qëllimisht nuk ka verifikim të të dhënave hyrëse, sepse së pari, dhe në "telnetin e kutisë" ekziston mundësia për të formatuar diskun e serverit, dhe së dyti, çështja e sigurisë në këtë artikull është lënë jashtë dhe për këtë arsye nuk ka asnjë fjalë për enkriptimin ose SSL.
Këtu ka vetëm 2 funksione (njëra prej të cilave është overload), dhe në përgjithësi kjo nuk është një praktikë shumë e mirë, megjithatë në kuadër të kësaj detyre më duket e arsyeshme ta lë gjithçka ashtu siç është.
boolean isRunning = true;
public void run(int port) {
(new Thread(()->{ try {
ServerSocket ss = new ServerSocket(port); // krijojmë soket serveri dhe e lidhim atë me portin e mësipërm
System.out.println("Port " + port + " është duke pritur për lidhje");
Socket socket = ss.accept();
System.out.println("E lidhur");
System.out.println();
// Marrim rrjedhat hyrëse dhe dalëse të soketit, tani mund të marrim dhe dërgojmë të dhëna klientit.
InputStream sin = socket.getInputStream();
OutputStream sout = socket.getOutputStream();
Map 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 = "Diçka shkoi keq... Kodi i gabimit: " + 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("Gabim: " + e.getMessage());
}
}).start();
System.out.println(buffer);
buffer = "";
}
}
catch(Exception x) {
System.out.println(x.getMessage());
}})).start();
}
Programi hap një port serveri, lexon nga të dhënat derisa të takohet simboli përfundimtar i komandës, transferon komandën në një proces të ri, dhe dalja nga procesi është ridrejtuar në soket. E thjeshtë si një automat Kalashnikovi.
Prandaj, për këtë funksion ka një mbushje me portin e paracaktuar:
public void run()
{
run(23);
}Po ashtu, funksioni qĂ« ndalon serverin â gjithashtu Ă«shtĂ« e thjeshtĂ«, ai ndĂ«rpret ciklin e pĂ«rhershĂ«m, duke shkelur kushtin e tij.
public void stop()
{
System.out.println("Server was stopped");
this.isRunning = false;
}Nuk i sjell kĂ«tu klasat testuese, ato janĂ« mĂ« poshtĂ« â gjithçka qĂ« ato bĂ«jnĂ« Ă«shtĂ« tĂ« kontrollojnĂ« funksionalitetin e metodave publike. TĂ« gjitha janĂ« nĂ« Git.
PĂ«rmbledhur, pĂ«r disa mbrĂ«mje mund tĂ« kuptoni parimet e veprimit tĂ« utiliteteve kryesore tĂ« konsolĂ«s. Tani, kur ne lidhemi me njĂ« kompjuter tĂ« largĂ«t, ne kuptojmĂ« se çfarĂ« po ndodh â magia ka ikur)
Pra, lidhjet:
Burimi: habr.com
