Inkomplu s-serje kontinwa ta 'artikoli ddedikati għall-implimentazzjonijiet tad-dwana tal-utilitajiet tal-console tal-Windows, ma nistgħux ma nmissux ma' TFTP (Trivial File Transfer Protocol) - protokoll sempliċi ta' trasferiment ta 'fajls.
Bħala l-aħħar darba, ejja ngħaddu fil-qosor fuq it-teorija, ara l-kodiċi li timplimenta funzjonalità simili għal dik meħtieġa, u tanalizzah. Aktar dettalji - taħt il-qatgħa
Mhux se nikkopja-pejst informazzjoni ta 'referenza, links li tradizzjonalment jistgħu jinstabu fl-aħħar tal-artikolu, jien ser ngħid biss li fil-qalba tiegħu, TFTP hija varjazzjoni simplifikata tal-protokoll FTP, li fiha l-issettjar tal-kontroll tal-aċċess tneħħa, u fil-fatt m'hemm xejn hawn ħlief kmandi biex tirċievi u tittrasferixxi fajl . Madankollu, sabiex l-implimentazzjoni tagħna ssir ftit aktar eleganti u adattata għall-prinċipji attwali tal-kitba tal-kodiċi, is-sintassi nbidlet ftit - dan ma jbiddilx il-prinċipji tal-operat, iżda l-interface, IMHO, isir ftit aktar loġiku u jgħaqqad l-aspetti pożittivi ta 'FTP u TFTP.
B'mod partikolari, meta tniedi, il-klijent jitlob l-indirizz IP tas-server u l-port li fih ikun miftuħ it-TFTP tad-dwana (minħabba l-inkompatibilità mal-protokoll standard, qiest li kien xieraq li tħalli lill-utent il-ħila li jagħżel port), wara li a konnessjoni sseħħ, bħala riżultat li l-klijent jista 'jibgħat wieħed mill-kmandi - tikseb jew tpoġġi, li tirċievi jew tibgħat fajl lis-server. Il-fajls kollha jintbagħtu fil-modalità binarja biex tissimplifika l-loġika.
Biex nimplimenta l-protokoll, tradizzjonalment użajt 4 klassijiet:
- TFTPClient
- TFTPServer
- TFTPClientTester
- TFTPServerTester
Minħabba l-fatt li l-klassijiet tal-ittestjar jeżistu biss għad-debugging ta 'dawk ewlenin, mhux se janalizzahom, iżda l-kodiċi se jkun fir-repożitorju jista' jinstab link għalih fl-aħħar tal-artiklu; Issa se nħares lejn il-klassijiet ewlenin.
TFTPClient
Il-kompitu ta 'din il-klassi huwa li tikkonnettja ma' server remot billi tuża l-ip u n-numru tal-port tagħha, aqra kmand mill-fluss ta 'input (f'dan il-każ, it-tastiera), teżaminaha, tittrasferiha lis-server, u, skond jekk int jeħtieġ li tibgħat jew tirċievi fajl, tittrasferih jew tikseb.
Il-kodiċi għat-tnedija tal-klijent biex jgħaqqad mas-server u stenna għal kmand mill-fluss ta 'input jidher bħal dan. Numru ta 'varjabbli globali li huma użati hawn huma deskritti barra l-artikolu, fit-test sħiħ tal-programm. Minħabba t-trivjalità tagħhom, ma niċċitahomx biex ma jgħabbix żżejjed l-artiklu.
public void run(String ip, int port)
{
this.ip = ip;
this.port = port;
try {
inicialization();
Scanner keyboard = new Scanner(System.in);
while (isRunning) {
getAndParseInput(keyboard);
sendCommand();
selector();
}
}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
Ejja mmorru fuq il-metodi msejħa f'dan il-blokk ta 'kodiċi:
Hawnhekk il-fajl jintbagħat - bl-użu ta 'skaner, aħna nippreżentaw il-kontenut tal-fajl bħala firxa ta' bytes, li niktbu wieħed wieħed fis-sokit, u wara nagħlquh u niftħu mill-ġdid (mhux l-aktar soluzzjoni ovvja, iżda tiggarantixxi r-rilaxx tar-riżorsi), u wara aħna nuru messaġġ dwar trasferiment b'suċċess.
private void put(String sourcePath, String destPath)
{
File src = new File(sourcePath);
try {
InputStream scanner = new FileInputStream(src);
byte[] bytes = scanner.readAllBytes();
for (byte b : bytes)
sout.write(b);
sout.close();
inicialization();
System.out.println("nDonen");
}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
Dan il-framment tal-kodiċi jiddeskrivi l-irkupru tad-dejta mis-server. Kollox huwa għal darb'oħra trivjali, l-ewwel blokk ta 'kodiċi biss huwa ta' interess. Sabiex tifhem eżattament kemm il-bytes jeħtieġ li jinqraw mis-sokit, trid tkun taf kemm jiżen il-fajl trasferit. Id-daqs tal-fajl fuq is-server huwa rappreżentat bħala numru sħiħ twil, għalhekk 4 bytes huma aċċettati hawnhekk, li sussegwentement jiġu kkonvertiti f'numru wieħed. Dan mhuwiex approċċ Java ħafna, huwa pjuttost simili għal SI, iżda jsolvi l-problema tiegħu.
Imbagħad kollox huwa trivjali - nirċievu numru magħruf ta 'bytes mis-sokit u niktbuhom f'fajl, u wara aħna nuru messaġġ ta' suċċess.
private void get(String sourcePath, String destPath){
long sizeOfFile = 0;
try {
byte[] sizeBytes = new byte[Long.SIZE];
for (int i =0; i< Long.SIZE/Byte.SIZE; i++)
{
sizeBytes[i] = (byte)sin.read();
sizeOfFile*=256;
sizeOfFile+=sizeBytes[i];
}
FileOutputStream writer = new FileOutputStream(new File(destPath));
for (int i =0; i < sizeOfFile; i++)
{
writer.write(sin.read());
}
writer.close();
System.out.println("nDONEn");
}
catch (Exception e){
System.out.println(e.getMessage());
}
}
Jekk ġie mdaħħal kmand ieħor għajr get jew put fit-tieqa tal-klijent, tissejjaħ il-funzjoni showErrorMessage, li tindika li l-input ma kienx korrett. Minħabba t-trivjalità, mhux se niċċitaha. Kemmxejn aktar interessanti hija l-funzjoni li tirċievi u tinqasam is-sekwenza tad-dħul. Aħna ngħaddu l-iskaner fih, li minnu nistennew li nirċievu linja separata minn żewġ spazji u li jkun fiha l-kmand, l-indirizz tas-sors u l-indirizz tad-destinazzjoni.
private void getAndParseInput(Scanner scanner)
{
try {
input = scanner.nextLine().split(" ");
typeOfCommand = input[0];
sourcePath = input[1];
destPath = input[2];
}
catch (Exception e) {
System.out.println("Bad input");
}
}
Tibgħat kmand—jitrażmetti l-kmand imdaħħal mill-iskaner għas-socket u jġiegħel li jintbagħat
private void sendCommand()
{
try {
for (String str : input) {
for (char ch : str.toCharArray()) {
sout.write(ch);
}
sout.write(' ');
}
sout.write('n');
}
catch (Exception e) {
System.out.print(e.getMessage());
}
}
Selettur huwa funzjoni li tiddetermina l-azzjonijiet tal-programm skont is-sekwenza mdaħħla. Kollox hawnhekk mhuwiex sabiħ ħafna u t-trick użat mhuwiex l-aħjar wieħed b'ħruġ sfurzat barra l-blokk tal-kodiċi, iżda r-raġuni ewlenija għal dan hija n-nuqqas f'Java ta 'xi affarijiet, bħal delegati f'C#, indikaturi tal-funzjoni minn C++, jew f' inqas il-goto terribbli u terribbli, li jippermettu li timplimenta dan beautifully. Jekk taf kif tagħmel il-kodiċi ftit aktar eleganti, nilqa' l-kritika fil-kummenti. Jidhirli li hawnhekk hemm bżonn dizzjunarju String-delegat, iżda m'hemm l-ebda delegat...
private void selector()
{
do{
if (typeOfCommand.equals("get")){
get(sourcePath, destPath);
break;
}
if (typeOfCommand.equals("put")){
put(sourcePath, destPath);
break;
}
showErrorMessage();
}
while (false);
}
}
TFTPServer
Il-funzjonalità tas-server hija differenti mill-funzjonalità tal-klijent, b'mod ġenerali, biss f'dak li kmandi jaslu għaliha mhux mit-tastiera, iżda mis-sokit. Uħud mill-metodi huma ġeneralment l-istess, għalhekk mhux se niċċitahom, se tmiss biss id-differenzi.
Biex tibda, jintuża l-metodu run, li jirċievi port bħala input u jipproċessa d-dejta tal-input mis-sokit f'linja eterna.
public void run(int port) {
this.port = port;
incialization();
while (true) {
getAndParseInput();
selector();
}
}
Il-metodu put, li jgeżwer il-metodu writeToFileFromSocket li jiftaħ fluss ta 'kitba għal fajl u jikteb il-bytes ta' input kollha mis-socket, juri messaġġ li jindika t-tlestija b'suċċess tat-trasferiment meta titlesta l-kitba.
private void put(String source, String dest){
writeToFileFromSocket();
System.out.print("nDonen");
};
private void writeToFileFromSocket()
{
try {
FileOutputStream writer = new FileOutputStream(new File(destPath));
byte[] bytes = sin.readAllBytes();
for (byte b : bytes) {
writer.write(b);
}
writer.close();
}
catch (Exception e){
System.out.println(e.getMessage());
}
}
Il-metodu get jirkupra l-fajl tas-server. Kif diġà ssemma fit-taqsima fuq in-naħa tal-klijent tal-programm, biex tittrasferixxi b'suċċess fajl għandek bżonn tkun taf id-daqs tiegħu, maħżun f'numru sħiħ twil, għalhekk qassejtha f'firxa ta '4 bytes, ittrasferihom byte b'byte għas-sokit, u mbagħad, wara li rċevejthom u assemblajthom fuq il-klijent f'numru lura, nittrasferixxi l-bytes kollha li jiffurmaw il-fajl, aqra mill-fluss ta 'input mill-fajl.
private void get(String source, String dest){
File sending = new File(source);
try {
FileInputStream readFromFile = new FileInputStream(sending);
byte[] arr = readFromFile.readAllBytes();
byte[] bytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(sending.length()).array();
for (int i = 0; i<Long.SIZE / Byte.SIZE; i++)
sout.write(bytes[i]);
sout.flush();
for (byte b : arr)
sout.write(b);
}
catch (Exception e){
System.out.println(e.getMessage());
}
};
Il-metodu getAndParseInput huwa l-istess bħal fil-klijent, l-unika differenza hija li jaqra d-dejta mis-socket aktar milli mit-tastiera. Il-kodiċi jinsab fir-repożitorju, bħal selettur.
F'dan il-każ, l-inizjalizzazzjoni titqiegħed fi blokka separata ta 'kodiċi, għaliex fi ħdan din l-implimentazzjoni, wara li jitlesta t-trasferiment, ir-riżorsi jiġu rilaxxati u okkupati mill-ġdid - għal darb'oħra biex jipprovdu protezzjoni kontra tnixxijiet tal-memorja.
private void incialization()
{
try {
serverSocket = new ServerSocket(port);
socket = serverSocket.accept();
sin = socket.getInputStream();
sout = socket.getOutputStream();
}
catch (Exception e) {
System.out.print(e.getMessage());
}
}
Biex tqassar:
Għadna kemm ktibna l-varjazzjoni tagħna stess fuq protokoll ta’ trasferiment tad-dejta sempliċi u sibna kif għandha taħdem. Fil-prinċipju, ma skoprejtx l-Amerika hawn u ma ktibtx ħafna affarijiet ġodda, iżda ma kienx hemm artikli simili fuq Habré, u bħala parti mill-kitba ta 'serje ta' artikli dwar l-utilitajiet cmd kien impossibbli li ma tmissx fuqha.
Referenzi:
Sors: www.habr.com