Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
laboratoare:laborator06 [2015/04/06 13:58] Andrei Roșu-Cojocaru |
laboratoare:laborator06 [2017/02/20 20:54] (current) |
||
|---|---|---|---|
| Line 19: | Line 19: | ||
| <code> | <code> | ||
| - | student@pdsd2015:/opt/android-sdk-linux/platform-tools$ ./adb devices | + | student@eim2016:/opt/android-sdk-linux/platform-tools$ ./adb devices |
| List of devices attached | List of devices attached | ||
| 0019531d59461f device | 0019531d59461f device | ||
| - | student@pdsd2015:/opt/android-sdk-linux/platform-tools$ ./adb -s 0019531d59461f shell | + | student@eim2016:/opt/android-sdk-linux/platform-tools$ ./adb -s 0019531d59461f shell |
| shell@n7000:/ $ su | shell@n7000:/ $ su | ||
| su | su | ||
| Line 33: | Line 33: | ||
| <note important>Pe Linux, în situația în care dispozitivul mobil este detectat, fără a se indica tipul său, este necesar să se pornească serverul de ADB cu drepturi de administrator: | <note important>Pe Linux, în situația în care dispozitivul mobil este detectat, fără a se indica tipul său, este necesar să se pornească serverul de ADB cu drepturi de administrator: | ||
| <code> | <code> | ||
| - | student@pdsd2015:/opt/android-sdk-linux/platform-tools$ ./adb devices | + | student@eim2016:/opt/android-sdk-linux/platform-tools$ ./adb devices |
| List of devices attached | List of devices attached | ||
| 0019531d59461f ???????????? | 0019531d59461f ???????????? | ||
| - | student@pdsd2015:/opt/android-sdk-linux/platform-tools$ sudo ./adb kill-server | + | student@eim2016:/opt/android-sdk-linux/platform-tools$ sudo ./adb kill-server |
| - | student@pdsd2015:/opt/android-sdk-linux/platform-tools$ sudo ./adb start-server | + | student@eim2016:/opt/android-sdk-linux/platform-tools$ sudo ./adb start-server |
| - | student@pdsd2015:/opt/android-sdk-linux/platform-tools$ sudo ./adb devices | + | student@eim2016:/opt/android-sdk-linux/platform-tools$ sudo ./adb devices |
| List of devices attached | List of devices attached | ||
| 0019531d59461f device | 0019531d59461f device | ||
| </code> | </code> | ||
| + | |||
| + | Pentru dispozitivele care nu permit conectarea cu ''adb shell'' in modul tethering [[http://stackoverflow.com/questions/9210152/set-up-device-for-development-no-permissions|soluție stackoverflow]], trebuie creat în Ubuntu fișierul ''/etc/udev/rules.d/51-android.rules'' și adăugat codul obținut cu ''lsusb'' pentru fabricantul telefonului. Odată dispozitivul de rețea obținut (de exemplu ''rndis0''), se folosește ''dhclient rndis0'' pentru a obține o adresă IP de la telefon. | ||
| Pe Windows, dacă dispozitivul mobil nu este detectat, poate fi necesară instalarea unor drivere suplimentare pentru stabilirea legăturii prin intermediul portului USB. | Pe Windows, dacă dispozitivul mobil nu este detectat, poate fi necesară instalarea unor drivere suplimentare pentru stabilirea legăturii prin intermediul portului USB. | ||
| Line 53: | Line 55: | ||
| <code> | <code> | ||
| - | student@pdsd2015:~$ sudo ifconfig usb0 | + | student@eim2016:~$ sudo ifconfig usb0 |
| usb0 Link encap:Ethernet HWaddr 32:ca:4b:1c:ff:7b | usb0 Link encap:Ethernet HWaddr 32:ca:4b:1c:ff:7b | ||
| inet addr:192.168.42.170 Bcast:192.168.42.255 Mask:255.255.255.0 | inet addr:192.168.42.170 Bcast:192.168.42.255 Mask:255.255.255.0 | ||
| Line 97: | Line 99: | ||
| Configurarea spațiului de adrese care este folosit poate fi configurat prin intermediul VirtualBox, accesând //File// → //Preferences// → //Network// → //Host Only Networks// | Configurarea spațiului de adrese care este folosit poate fi configurat prin intermediul VirtualBox, accesând //File// → //Preferences// → //Network// → //Host Only Networks// | ||
| - | {{ :laboratoare:laborator06:virtualbox01.png?nolink&600 }} | + | {{ :laboratoare:laborator06:virtualbox01.png?nolink&500 }} |
| - | {{ :laboratoare:laborator06:virtualbox02.png?nolink&600 }} | + | {{ :laboratoare:laborator06:virtualbox02.png?nolink&500 }} |
| Adresa IP care a fost atașată fiecărui dispozitiv virtual Genymotion poate fi verificată: | Adresa IP care a fost atașată fiecărui dispozitiv virtual Genymotion poate fi verificată: | ||
| * folosind comanda ''adb devices''; <code> | * folosind comanda ''adb devices''; <code> | ||
| - | student@pdsd2015:/opt/android-sdk-linux/platform-tools$ ./adb devices | + | student@eim2016:/opt/android-sdk-linux/platform-tools$ ./adb devices |
| List of devices attached | List of devices attached | ||
| 192.168.56.101:5555 device | 192.168.56.101:5555 device | ||
| </code> | </code> | ||
| - | * prin intermediul plugin-ului Genymotion pentru mediul integrat de dezvoltare Eclipse Luna SR1a (4.4.1) - Ctrl + 6. | + | * prin intermediul plugin-ului Genymotion pentru mediile integrate de dezvoltare. |
| {{ :laboratoare:laborator06:genymotion_ip_addresses.png?nolink&700 }} | {{ :laboratoare:laborator06:genymotion_ip_addresses.png?nolink&700 }} | ||
| Conectivitatea dintre mașina fizică și dispozitivul virtual poate fi verificată folosind comanda ''ping''. <code> | Conectivitatea dintre mașina fizică și dispozitivul virtual poate fi verificată folosind comanda ''ping''. <code> | ||
| - | student@pdsd2015:~$ ping 192.168.56.101 | + | student@eim2016:~$ ping 192.168.56.101 |
| Pinging 192.168.56.101 with 32 bytes of data: | Pinging 192.168.56.101 with 32 bytes of data: | ||
| Reply from 192.168.56.101: bytes=32 time<1ms TTL=64 | Reply from 192.168.56.101: bytes=32 time<1ms TTL=64 | ||
| Line 134: | Line 136: | ||
| * prin inspectarea ferestrei în care este afișat emulatorul, având forma //Android Emulator (55nr)//, unde nr poate lua valori cuprinse între 54 și 87 (doar valori impare - pentru portul de consolă, valorile pare fiind rezervate pentru portul adb); astfel, sunt suportate maxim 16 instanțe de dispozitive virtuale Android simultan; | * prin inspectarea ferestrei în care este afișat emulatorul, având forma //Android Emulator (55nr)//, unde nr poate lua valori cuprinse între 54 și 87 (doar valori impare - pentru portul de consolă, valorile pare fiind rezervate pentru portul adb); astfel, sunt suportate maxim 16 instanțe de dispozitive virtuale Android simultan; | ||
| - | {{ :laboratoare:laborator06:android_virtual_device_port.png?nolink&400 }} | + | {{ :laboratoare:laborator06:android_virtual_device_port.png?nolink&600 }} |
| * prin rularea comenzii ''adb devices'' <code> | * prin rularea comenzii ''adb devices'' <code> | ||
| - | student@pdsd2015:/opt/android-sdk-linux/platform-tools$ ./adb devices | + | student@eim2016:/opt/android-sdk-linux/platform-tools$ ./adb devices |
| List of devices attached | List of devices attached | ||
| emulator-5554 device | emulator-5554 device | ||
| Line 143: | Line 145: | ||
| Conectarea la consola dispozitivului virtual Android se face prin comanda: <code> | Conectarea la consola dispozitivului virtual Android se face prin comanda: <code> | ||
| - | student@pdsd2015:~$ telnet localhost 55nr | + | student@eim2016:~$ telnet localhost 55nr |
| </code> | </code> | ||
| specificându-se portul pe care rulează emulatorul. | specificându-se portul pe care rulează emulatorul. | ||
| - | În consolă, realizarea unei legături între mașina fizică și dispozitivul virtual Android se face prin [[http://developer.android.com/tools/devices/emulator.html#portredirection|redirectarea portului]], folosind comanda ''redir'', aceasta suportând mai multe opțiuni: | + | În consolă, realizarea unei legături între mașina fizică și dispozitivul virtual Android se face prin [[http://developer.android.com/tools/help/emulator.html#redirection|redirectarea portului]], folosind comanda ''redir'', aceasta suportând mai multe opțiuni: |
| * ''list''; | * ''list''; | ||
| * ''add''; | * ''add''; | ||
| Line 160: | Line 162: | ||
| <code> | <code> | ||
| - | student@pdsd2015:~$ telnet localhost 5554 | + | student@eim2016:~$ telnet localhost 5554 |
| Android Console: type 'help' for a list of commands | Android Console: type 'help' for a list of commands | ||
| OK | OK | ||
| Line 175: | Line 177: | ||
| exit | exit | ||
| Connection to host lost. | Connection to host lost. | ||
| - | student@pdsd2015:~$ | + | student@eim2016:~$ |
| </code> | </code> | ||
| Line 218: | Line 220: | ||
| <code java> | <code java> | ||
| String hostname = "localhost"; | String hostname = "localhost"; | ||
| - | int port = 2015; | + | int port = 2016; |
| Socket socket = new Socket(hostname, port); | Socket socket = new Socket(hostname, port); | ||
| </code> | </code> | ||
| Line 313: | Line 315: | ||
| Se dorește interogarea serverului National Institute of Standards & Technology, care oferă un serviciu de interogare a datei și orei curente, cu o precizie ridicată, conform [[https://tools.ietf.org/html/rfc867|Daytime Protocol (RFC-867)]]. | Se dorește interogarea serverului National Institute of Standards & Technology, care oferă un serviciu de interogare a datei și orei curente, cu o precizie ridicată, conform [[https://tools.ietf.org/html/rfc867|Daytime Protocol (RFC-867)]]. | ||
| - | {{ :laboratoare:laborator06:daytime_protocol.png?nolink&400 }} | + | {{ :laboratoare:laborator06:01day_time_protocol.png?nolink&400 }} |
| În acest sens, se va deschide un socket TCP, prin interogarea serverului disponibil la adresa [[time-b.nist.gov|]], pe portul 13, în cadrul unui fir de execuție separat (clasa ''NISTCommunicationThread''). Întrucât nu este necesară decât operația de primire a unor date, se va crea doar un obiect de tip ''BufferedReader'', citindu-se două linii (una fiind vidă - așadar ignorată, cealaltă conținând informațiile necesare, care se doresc a fi afișate). Întrucât modificarea conținutului unui control grafic nu poate fi realizată decât din contextul firului de execuție în care a fost creat, acesta va fi obținut prin parametrul metodei ''post()'' a obiectului respectiv, doar aici fiind permisă asocierea conținutului solicitat. În momentul în care datele au fost preluate, socket-ul TCP poate fi închis. Pe fiecare eveniment de tip apăsare a butonului se va crea un fir de execuție dedicat în care se va instanția un obiect de tip ''Socket''. | În acest sens, se va deschide un socket TCP, prin interogarea serverului disponibil la adresa [[time-b.nist.gov|]], pe portul 13, în cadrul unui fir de execuție separat (clasa ''NISTCommunicationThread''). Întrucât nu este necesară decât operația de primire a unor date, se va crea doar un obiect de tip ''BufferedReader'', citindu-se două linii (una fiind vidă - așadar ignorată, cealaltă conținând informațiile necesare, care se doresc a fi afișate). Întrucât modificarea conținutului unui control grafic nu poate fi realizată decât din contextul firului de execuție în care a fost creat, acesta va fi obținut prin parametrul metodei ''post()'' a obiectului respectiv, doar aici fiind permisă asocierea conținutului solicitat. În momentul în care datele au fost preluate, socket-ul TCP poate fi închis. Pe fiecare eveniment de tip apăsare a butonului se va crea un fir de execuție dedicat în care se va instanția un obiect de tip ''Socket''. | ||
| Line 319: | Line 321: | ||
| De remarcat faptul că obiectele interfeței grafice sunt definite ca membrii protejați ai clasei activitate, întrucât accesul acestea trebuie să poată fi accesate și din clasele interne, fără a se mai obține referința către ele prin metoda ''findViewById()'', care depreciază performanțele aplicației Android. | De remarcat faptul că obiectele interfeței grafice sunt definite ca membrii protejați ai clasei activitate, întrucât accesul acestea trebuie să poată fi accesate și din clasele interne, fără a se mai obține referința către ele prin metoda ''findViewById()'', care depreciază performanțele aplicației Android. | ||
| - | <file java DaytimeProtocol.java> | + | <file java DayTimeProtocolActivity.java> |
| - | import java.io.BufferedReader; | + | package ro.pub.cs.systems.eim.lab06.daytimeprotocol.views; |
| - | import java.io.IOException; | + | |
| - | import java.net.Socket; | + | |
| - | import java.net.UnknownHostException; | + | |
| - | import android.app.Activity; | + | import android.os.AsyncTask; |
| + | import android.support.v7.app.AppCompatActivity; | ||
| import android.os.Bundle; | import android.os.Bundle; | ||
| import android.util.Log; | import android.util.Log; | ||
| - | import android.view.Menu; | ||
| - | import android.view.MenuItem; | ||
| import android.view.View; | import android.view.View; | ||
| import android.widget.Button; | import android.widget.Button; | ||
| import android.widget.TextView; | import android.widget.TextView; | ||
| - | public class DaytimeProtocolActivity extends Activity { | + | import java.io.BufferedReader; |
| + | import java.io.IOException; | ||
| + | import java.net.Socket; | ||
| + | import java.net.UnknownHostException; | ||
| + | |||
| + | import ro.pub.cs.systems.eim.lab06.daytimeprotocol.R; | ||
| + | import ro.pub.cs.systems.eim.lab06.daytimeprotocol.general.Constants; | ||
| + | import ro.pub.cs.systems.eim.lab06.daytimeprotocol.general.Utilities; | ||
| + | |||
| + | public class DayTimeProtocolActivity extends AppCompatActivity { | ||
| + | |||
| + | private Button getInformationButton; | ||
| + | private TextView daytimeProtocolTextView; | ||
| + | |||
| + | private class NISTCommunicationAsyncTask extends AsyncTask<Void, Void, String> { | ||
| - | protected Button getInformationButton; | ||
| - | protected TextView daytimeProtocolTextView; | ||
| - | |||
| - | protected class NISTCommunicationThread extends Thread { | ||
| - | | ||
| @Override | @Override | ||
| - | public void run() { | + | protected String doInBackground(Void... params) { |
| + | String dayTimeProtocol = null; | ||
| try { | try { | ||
| - | Socket socket = new Socket ( | + | Socket socket = new Socket(Constants.NIST_SERVER_HOST, Constants.NIST_SERVER_PORT); |
| - | Constants.NIST_SERVER_HOST, | + | |
| - | Constants.NIST_SERVER_PORT | + | |
| - | ); | + | |
| BufferedReader bufferedReader = Utilities.getReader(socket); | BufferedReader bufferedReader = Utilities.getReader(socket); | ||
| bufferedReader.readLine(); | bufferedReader.readLine(); | ||
| - | final String daytimeProtocol = bufferedReader.readLine(); | + | dayTimeProtocol = bufferedReader.readLine(); |
| - | daytimeProtocolTextView.post(new Runnable() { | + | Log.d(Constants.TAG, "The server returned: " + dayTimeProtocol); |
| - | @Override | + | |
| - | public void run() { | + | |
| - | daytimeProtocolTextView.setText(daytimeProtocol); | + | |
| - | } | + | |
| - | }); | + | |
| - | socket.close(); | + | |
| } catch (UnknownHostException unknownHostException) { | } catch (UnknownHostException unknownHostException) { | ||
| - | Log.e(Constants.TAG, "An exception has occurred: "+unknownHostException.getMessage()); | + | Log.d(Constants.TAG, unknownHostException.getMessage()); |
| - | if (Constants.DEBUG) { | + | if (Constants.DEBUG) { |
| unknownHostException.printStackTrace(); | unknownHostException.printStackTrace(); | ||
| } | } | ||
| } catch (IOException ioException) { | } catch (IOException ioException) { | ||
| - | Log.e(Constants.TAG, "An exception has occurred: "+ioException.getMessage()); | + | Log.d(Constants.TAG, ioException.getMessage()); |
| if (Constants.DEBUG) { | if (Constants.DEBUG) { | ||
| ioException.printStackTrace(); | ioException.printStackTrace(); | ||
| } | } | ||
| } | } | ||
| + | return dayTimeProtocol; | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | protected void onPostExecute(String result) { | ||
| + | daytimeProtocolTextView.setText(result); | ||
| } | } | ||
| } | } | ||
| - | | + | |
| - | protected ButtonClickListener buttonClickListener = new ButtonClickListener(); | + | private ButtonClickListener buttonClickListener = new ButtonClickListener(); |
| - | | + | private class ButtonClickListener implements Button.OnClickListener { |
| - | protected class ButtonClickListener implements Button.OnClickListener { | + | |
| - | + | ||
| @Override | @Override | ||
| public void onClick(View view) { | public void onClick(View view) { | ||
| - | new NISTCommunicationThread().start(); | + | NISTCommunicationAsyncTask nistCommunicationAsyncTask = new NISTCommunicationAsyncTask(); |
| + | nistCommunicationAsyncTask.execute(); | ||
| } | } | ||
| + | |||
| } | } | ||
| - | | + | |
| @Override | @Override | ||
| protected void onCreate(Bundle savedInstanceState) { | protected void onCreate(Bundle savedInstanceState) { | ||
| super.onCreate(savedInstanceState); | super.onCreate(savedInstanceState); | ||
| - | setContentView(R.layout.activity_daytime_protocol); | + | setContentView(R.layout.activity_day_time_protocol); |
| - | + | ||
| daytimeProtocolTextView = (TextView)findViewById(R.id.daytime_protocol_text_view); | daytimeProtocolTextView = (TextView)findViewById(R.id.daytime_protocol_text_view); | ||
| - | | + | |
| getInformationButton = (Button)findViewById(R.id.get_information_button); | getInformationButton = (Button)findViewById(R.id.get_information_button); | ||
| getInformationButton.setOnClickListener(buttonClickListener); | getInformationButton.setOnClickListener(buttonClickListener); | ||
| Line 425: | Line 431: | ||
| android:layout_height="match_parent" | android:layout_height="match_parent" | ||
| android:orientation="vertical" | android:orientation="vertical" | ||
| - | tools:context="ro.pub.cs.systems.pdsd.lab06.singlethreadedserver.views.SingleThreadedActivity" > | + | tools:context="ro.pub.cs.systems.eim.lab06.singlethreadedserver.views.SingleThreadedActivity" > |
| | | ||
| <EditText | <EditText | ||
| Line 500: | Line 506: | ||
| public void stopServer() { | public void stopServer() { | ||
| isRunning = false; | isRunning = false; | ||
| - | try { | + | new Thread(new Runnable() { |
| - | serverSocket.close(); | + | @Override |
| - | } catch(IOException ioException) { | + | public void run() { |
| - | Log.e(Constants.TAG, "An exception has occurred: "+ioException.getMessage()); | + | try { |
| - | if (Constants.DEBUG) { | + | if (serverSocket != null) { |
| - | ioException.printStackTrace(); | + | serverSocket.close(); |
| + | } | ||
| + | Log.v(Constants.TAG, "stopServer() method invoked "+serverSocket); | ||
| + | } catch(IOException ioException) { | ||
| + | Log.e(Constants.TAG, "An exception has occurred: "+ioException.getMessage()); | ||
| + | if (Constants.DEBUG) { | ||
| + | ioException.printStackTrace(); | ||
| + | } | ||
| + | } | ||
| } | } | ||
| - | } | + | }).start(); |
| } | } | ||
| | | ||
| Line 543: | Line 557: | ||
| </file> | </file> | ||
| - | {{ :laboratoare:laborator06:single_threaded_server.png?nolink&400 }} | + | {{ :laboratoare:laborator06:02single_threaded_server.png?nolink&400 }} |
| Prin intermediul utilitarului ''nc'' (apelat cu adresa Internet și portul serverului) se poate interoga mesajul care a fost transmis. De asemenea, comanda ''time'' măsoară timpul în care a fost executată operația respectivă. | Prin intermediul utilitarului ''nc'' (apelat cu adresa Internet și portul serverului) se poate interoga mesajul care a fost transmis. De asemenea, comanda ''time'' măsoară timpul în care a fost executată operația respectivă. | ||
| <code> | <code> | ||
| - | student@pdsd2015:~$ nc 192.168.56.101 2015 | + | student@eim2016:~$ nc 192.168.56.101 2016 |
| - | Hello, PDSD Student! | + | Hello, EIM Student! |
| - | student@pdsd2015:~$ time nc 192.168.56.101 2015 | + | student@eim2016:~$ time nc 192.168.56.101 2016 |
| - | Hello, PDSD Student! | + | Hello, EIM Student! |
| real 0m0.009s | real 0m0.009s | ||
| Line 649: | Line 663: | ||
| **1.** În contul Github personal, să se creeze un depozit denumit 'Laborator06'. Inițial, acesta trebuie să fie gol (nu trebuie să bifați nici adăugarea unui fișier ''README.md'', nici a fișierului ''.gitignore'' sau a a fișierului ''LICENSE''). | **1.** În contul Github personal, să se creeze un depozit denumit 'Laborator06'. Inițial, acesta trebuie să fie gol (nu trebuie să bifați nici adăugarea unui fișier ''README.md'', nici a fișierului ''.gitignore'' sau a a fișierului ''LICENSE''). | ||
| - | **2.** Să se cloneze în directorul de pe discul local conținutul depozitului la distanță de la [[https://www.github.com/pdsd2015/Laborator06|]]. | + | **2.** Să se cloneze în directorul de pe discul local conținutul depozitului la distanță de la [[https://www.github.com/eim2016/Laborator06|]]. |
| În urma acestei operații, directorul Laborator06 va trebui să se conțină directoarele ''labtasks'', ''samples'' și ''solutions''. | În urma acestei operații, directorul Laborator06 va trebui să se conțină directoarele ''labtasks'', ''samples'' și ''solutions''. | ||
| <code> | <code> | ||
| - | student@pdsd2015:~$ git clone https://www.github.com/pdsd2015/Laborator06 | + | student@eim2016:~$ git clone https://www.github.com/eim2016/Laborator06.git |
| </code> | </code> | ||
| **3.** Să se încarce conținutul descărcat în cadrul depozitului 'Laborator06' de pe contul Github personal. <code> | **3.** Să se încarce conținutul descărcat în cadrul depozitului 'Laborator06' de pe contul Github personal. <code> | ||
| - | student@pdsd2015:~$ cd Laborator06 | + | student@eim2016:~$ cd Laborator06 |
| - | student@pdsd2015:~/Laborator06$ git remote add Laborator06_perfectstudent https://github.com/perfectstudent/Laborator06 | + | student@eim2016:~/Laborator06$ git remote add Laborator06_perfectstudent https://github.com/perfectstudent/Laborator06 |
| - | student@pdsd2015:~/Laborator06$ git push Laborator06_perfectstudent master | + | student@eim2016:~/Laborator06$ git push Laborator06_perfectstudent master |
| </code> | </code> | ||
| - | **4.** Să se importe în mediul integrat de dezvoltare Eclipse Luna SR1a (4.4.1) proiectul ''01-FTPServerWelcomeMessage'' din directorul ''labtasks''. | + | **4.** Să se importe în mediul integrat de dezvoltare preferat (Android Studio sau Eclipse) proiectul ''FTPServerWelcomeMessage'' din directorul ''labtasks''. |
| Se cere să se implementeze o aplicație Android care citește mesajul de întâmpinare transmis în momentul în care se realizează o conexiune către un server FTP. | Se cere să se implementeze o aplicație Android care citește mesajul de întâmpinare transmis în momentul în care se realizează o conexiune către un server FTP. | ||
| Line 671: | Line 685: | ||
| În cazul în care mesajul de întâmpinare conține mai multe linii, mesajul este precedat de șirul de caractere ''220-'' (reținut în ''Constants.FTP_MULTILINE_START_CODE''). Mesajul se încheie fie cu șirul de caractere ''220'', fie cu un șir de caractere precedat de ''220 '' (valori stocate în ''Constants.FTP_MULTILINE_END_CODE1'', respectiv ''Constants.FTP_MULTILINE_END_CODE2''). | În cazul în care mesajul de întâmpinare conține mai multe linii, mesajul este precedat de șirul de caractere ''220-'' (reținut în ''Constants.FTP_MULTILINE_START_CODE''). Mesajul se încheie fie cu șirul de caractere ''220'', fie cu un șir de caractere precedat de ''220 '' (valori stocate în ''Constants.FTP_MULTILINE_END_CODE1'', respectiv ''Constants.FTP_MULTILINE_END_CODE2''). | ||
| - | {{ :laboratoare:laborator06:ftp_server_welcome_message.png?nolink&400 }} | + | {{ :laboratoare:laborator06:03ftp_server_welcome_message.png?nolink&400 }} |
| - | Operațiile care trebuie realizate pe metoda ''run()'' a firului de execuție ce gestionează comunicația cu serverul FTP sunt: | + | Operațiile care trebuie realizate pe metoda ''doInBackground()'' a firului de execuție ce gestionează comunicația cu serverul FTP sunt: |
| - deschiderea unui socket care primește ca parametrii: | - deschiderea unui socket care primește ca parametrii: | ||
| - | - adresa Internet a serverului FTP (precizată anterior de utilizator, preluată din câmpul text ''FTPServerAddressEditText'') | + | - adresa Internet a serverului FTP (precizată anterior de utilizator, preluată din câmpul text ''FTPServerAddressEditText'', transmis ca parametru al metodei - ''params[0]'') |
| - portul 21 (preluat din ''Constants.FTP_PORT''). | - portul 21 (preluat din ''Constants.FTP_PORT''). | ||
| - obținerea fluxului de intrare atașat socket-ului, printr-un apel al metodei ''Utilities.getBufferedReader()''; | - obținerea fluxului de intrare atașat socket-ului, printr-un apel al metodei ''Utilities.getBufferedReader()''; | ||
| Line 683: | Line 697: | ||
| - nu este egală cu ''220'' (preluat din ''Constants.FTP_MULTILINE_END_CODE1''); | - nu este egală cu ''220'' (preluat din ''Constants.FTP_MULTILINE_END_CODE1''); | ||
| - nu începe cu ''220 '' (preluat din ''Constants.FTP_MULTILINE_END_CODE2''); | - nu începe cu ''220 '' (preluat din ''Constants.FTP_MULTILINE_END_CODE2''); | ||
| - | - valoarea primită de la serverul FTP este inclusă în câmpul text ''welcomeMEssageTextView''; | + | - valoarea primită de la serverul FTP este inclusă în câmpul text ''welcomeMEssageTextView'' (informația se transmite, pe măsură ce este primită, prin metoda ''publishProgress()'' care face să se invoce automat metoda de callback ''onProgressUpdate()'' executată pe firul de execuție principal al aplicației Android, la care se oferă acces la controalele grafice); |
| - altfel, mesajul este ignorat. | - altfel, mesajul este ignorat. | ||
| - închiderea socket-ului. | - închiderea socket-ului. | ||
| - | Să se verifice mesajul afișat în momentul în care se realizează o conexiune la serverul ''ftp.ngc.com''. | + | Să se verifice mesajul afișat în momentul în care se realizează o conexiune la serverul [[ftp.ngc.com|]]. |
| - | **5.** Să se importe în mediul integrat de dezvoltare Eclipse Luna SR1a (4.4.1) proiectul ''02-SingleThreadedServer'' din directorul ''labtasks''. | + | **5.** Să se importe în mediul integrat de dezvoltare preferat (Android Studio sau Eclipse) proiectul ''SingleThreadedServer'' din directorul ''labtasks''. |
| - | Acesta reprezintă o aplicație Android care implementează un server ce ascultă pe un port (2015, în ''Constants.SERVER_PORT'') solicitări de conexiune provenite de la clienți. | + | Acesta reprezintă o aplicație Android care implementează un server ce ascultă pe un port (2016, în ''Constants.SERVER_PORT'') solicitări de conexiune provenite de la clienți. |
| Pe același fir de execuție pe care se face așteptarea, este realizată și transmiterea mesajului către client, preluat dintr-un câmp text. | Pe același fir de execuție pe care se face așteptarea, este realizată și transmiterea mesajului către client, preluat dintr-un câmp text. | ||
| Line 701: | Line 715: | ||
| Preluarea invocărilor de la clienți este realizată doar atâta timp cât serverul se află în execuție. | Preluarea invocărilor de la clienți este realizată doar atâta timp cât serverul se află în execuție. | ||
| - | === | + | ==== Linux ==== |
| - | + | ||
| - | **Linux** | + | |
| Citirea mesajelor se face cu ''nc'' care primește ca parametrii adresa Internet și portul serverului de pe dispozitivul Android. Prin utilitarul ''time'' se verifică durata operației respective. | Citirea mesajelor se face cu ''nc'' care primește ca parametrii adresa Internet și portul serverului de pe dispozitivul Android. Prin utilitarul ''time'' se verifică durata operației respective. | ||
| <code> | <code> | ||
| - | student@pdsd2015:~$ nc 192.168.56.101 2015 | + | student@eim2016:~$ nc 192.168.56.101 2016 |
| - | Hello, PDSD Student! | + | Hello, EIM Student! |
| - | student@pdsd2015:~$ time nc 192.168.56.101 2015 | + | student@eim2016:~$ time nc 192.168.56.101 2016 |
| - | Hello, PDSD Student! | + | Hello, EIM Student! |
| real 0m0.009s | real 0m0.009s | ||
| Line 718: | Line 730: | ||
| </code> | </code> | ||
| - | **Windows** | + | ==== Windows ==== |
| Citirea mesajelor se face cu ''telnet'' care primește ca parametrii adresa Internet și portul serverului de pe dispozitivul Android. | Citirea mesajelor se face cu ''telnet'' care primește ca parametrii adresa Internet și portul serverului de pe dispozitivul Android. | ||
| Line 735: | Line 747: | ||
| <code> | <code> | ||
| - | C:\Users\Student> telnet 192.168.56.101 2015 | + | C:\Users\Student> telnet 192.168.56.101 2016 |
| Start Server | Start Server | ||
| Connection to host lost. | Connection to host lost. | ||
| - | C:\Users\Student> telnet 192.168.56.101 2015 | + | C:\Users\Student> telnet 192.168.56.101 2016 |
| - | Connecting To 192.168.56.101...Could not open connection to the host, on port 2015: Connect failed | + | Connecting To 192.168.56.101...Could not open connection to the host, on port 2016: Connect failed |
| </code> | </code> | ||
| - | === | + | ===== ===== |
| **a)** Să se trimită aplicația Android în fundal prin apăsarea tastei //Home//. Verificați conectivitatea cu serverul. De ce sunt tratate cererile în continuare? | **a)** Să se trimită aplicația Android în fundal prin apăsarea tastei //Home//. Verificați conectivitatea cu serverul. De ce sunt tratate cererile în continuare? | ||
| Line 768: | Line 780: | ||
| public void onDestroy() { | public void onDestroy() { | ||
| super.onDestroy(); | super.onDestroy(); | ||
| - | serverThread.stopServer(); | + | if (serverThread != null) { |
| + | serverThread.stopServer(); | ||
| + | } | ||
| } | } | ||
| </code> | </code> | ||
| Line 789: | Line 803: | ||
| **d)** Să se implementeze comunicația pentru fiecare conexiune dintre client și server pe un fir de execuție separat, astfel încât pe server, gestiunea solicitărilor provenite de la clienți să nu fie afectată. | **d)** Să se implementeze comunicația pentru fiecare conexiune dintre client și server pe un fir de execuție separat, astfel încât pe server, gestiunea solicitărilor provenite de la clienți să nu fie afectată. | ||
| + | **6.** Să se importe în mediul integrat de dezvoltare preferat (Android Studio sau Eclipse) proiectul ''ClientServerCommunication'' din directorul ''labtasks''. | ||
| + | |||
| + | Acesta reprezintă o aplicație Android având două fragmente, implementând atât un server cât și un client: | ||
| + | - serverul dispune de un câmp text prin intermediul căruia: | ||
| + | - pot fi realizate diferite operații asupra sa: | ||
| + | - pornire, prin introducerea mesajului //Start Server//; | ||
| + | - oprire, prin introducerea mesajului //Stop Server//. | ||
| + | - se poate preciza un mesaj care să fie transmis către client prin intermediul canalului de comunicație; | ||
| + | - clientul dispune de două câmpuri text, prin care se precizează parametrii de conexiune la server (adresa de Internet / portul) precum și un buton prin intermediul căruia se realizează legătura propriu-zisă, fiind preluată informația din cadrul canalului de comunicație și afișată corespunzător. | ||
| + | |||
| + | {{ :laboratoare:laborator06:04client_server_communication.png?nolink&400 }} | ||
| + | |||
| + | **a)** Să se implementeze funcționalitatea serverului. | ||
| + | |||
| + | În clasa ''ComunicationThread'' din fragmentul asociat serverului: | ||
| + | - se obține o referință către fluxul de ieșire asociat socket-ului, prin intermediul metodei ajutătoare ''Utilities.getWriter()''; | ||
| + | - se scrie o linie conținând textul din ''serverTextEditText''. | ||
| + | |||
| + | **b)** Să se implementeze funcționalitatea clientului. | ||
| + | |||
| + | În clasa ''ClientAsyncTask'' din fragmentul asociat serverului: | ||
| + | - se resetează conținutul câmpului text ''serverMessageTextView'', astfel încât acesta să conțină șirul vid; acest lucru este realizat înainte de a rula firul de execuție dedicat, așadar pe metoda ''onPreExecute()''; | ||
| + | - se obțin parametrii de conexiune la server (adresa de Internet, obținută din câmpul text ''serverAddressEditText'' și portul, obținut din câmpul text ''serverPortEditText''); aceștia sunt transmiși prin intermediul argumentelor metodei ''doInBackground()''; | ||
| + | - se deschide un socket, folosind configurația precizată de utilizator; | ||
| + | - se obține o referință către fluxul de intrare asociat socket-ului, prin intermediul metodei ajutătoare ''Utilities.getReader()''; | ||
| + | - se citesc linii din contextul canalului de comunicație, atâta timp cât nu se întâlnește ''EOF'' (nu se întoarce valoarea ''null''), valoarea fiind concatenată la câmpul text ''serverMessageTextView''; acest lucru este realizat prin transmiterea liniilor către firul de execuție principal - al interfeței grafice - (unde controalele grafice sunt accesibile), prin intermediul metodei ''publishProgress()'' care determină apelul metodei de callback ''onPublishProgress()''; | ||
| + | - se închide socketul. | ||
| + | |||
| + | <note important>Accesul la controalele grafice trebuie să fie realizat numai din contextul firului de execuție asociat interfeței cu utilizatorul.</note> | ||
| + | |||
| + | **c)** Să se pornească serverul (se introduce textul //Start Server//). În client, să se verifice valoarea furnizată în cazul în care se introduc valorile ''127.0.0.1'' / ''2016'', respectiv ''localhost'' / ''2016''. | ||
| + | |||
| + | Să se oprească serverul (se introduce textul //Stop Server//). Să se verifice ce valori sunt furnizate în această situație. | ||
| + | |||
| + | **d)** (doar Linux) Să se creeze o listă cu procesele care rulează la momentul curent, textul putând fi obținut, linie cu linie, prin intermediul unei conexiuni pe portul 2016, serverul fiind astfel simulat pe mașina fizică. | ||
| + | |||
| + | <code> | ||
| + | student@eim2016:~$ ps a | while read x; do echo "$x" | nc -l 2016; done | ||
| + | </code> | ||
| + | |||
| + | <note tip>Pe mașinile Debian, comanda ''nc'' se rulează cu opțiunea suplimentară ''-p'' pentru a se indica portul pe care se dorește ca acesta să accepte invocările.</note> | ||
| + | |||
| + | Să se folosească clientul pentru a citi, linie cu linie, valorile furnizate de script-ul anterior. Va trebui precizată adresa mașinii fizice (în funcție de configurația folosită) și portul 2016. | ||
| + | |||
| + | {{ :laboratoare:laborator06:05client_server_communication.png?nolink&400 }} | ||
| + | |||
| + | **7.** Să se importe în mediul integrat de dezvoltare preferat (Android Studio sau Eclipse) proiectul ''PheasantGame'' din directorul ''labtasks''. | ||
| + | |||
| + | Acesta reprezintă o aplicație Android care implementează jocul Fazan în limba engleză, atât partea de server, cât și partea de client. | ||
| + | |||
| + | Vor fi folosite următoarele **reguli de joc**: | ||
| + | - clientul trimite un cuvânt serverului; | ||
| + | - serverul verifică dacă nu s-a solicitat terminarea jocului, situație în care continuă analiza termenului respectiv; | ||
| + | - dacă s-a primit un cuvânt care are prefixul așteptat, termenul existând în limba engleză, se caută un alt cuvânt care începe cu ultimele 2 litere ale termenului: | ||
| + | - dacă există un astfel de cuvânt, acesta fiind transmis înapoi clientului; | ||
| + | - altfel, se semnalează faptul că jocul s-a terminat; | ||
| + | - altfel, se trimite înapoi cuvântul primit pentru a semnala faptul că există o problemă. | ||
| + | |||
| + | {{ :laboratoare:laborator06:06pheasant_game.png?nolink&400 }} | ||
| + | |||
| + | Astfel, serverul va avea următoarea funcționare: | ||
| + | - dacă se primește //End Game// (stocat în ''Constants.END_GAME''), pentru a se indica faptul că nu se mai dorește continuarea jocului sau clientul a fost închis (nu găsește nici un cuvânt cu prefixul solicitat), serverul își termină execuția; | ||
| + | - altfel, serverul verifică dacă termenul care a fost primit reprezintă un cuvânt valid în limba engleză (accesând în acest sens pagina Internet [[http://www.wordhippo.com/what-is/words-starting-with/|]]) - se folosește metoda ''Utilities.wordValidation()''; | ||
| + | - dacă termenul este valid: | ||
| + | - verifică dacă termenul începe cu prefixul solicitat (ultimele 2 litere ale cuvântului pe care l-a trimis anterior) - în acest sens, trebuie reținut cel mai recent cuvânt transmis / prefixul așteptat; | ||
| + | - în caz afirmativ: | ||
| + | - identifică prefixul cuvântului pe care trebuie să îl formeze (ultimele 2 litere ale cuvântului primit); | ||
| + | - realizează o interogare la nivelul paginii Internet [[http://www.wordhippo.com/what-is/words-starting-with/|]] pentru a obține lista cuvintelor care respectă constrângerea respectivă - se folosește metoda ''Utilities.getWordListStartingWith()'' care furnizează un obiect ''List<String>''; | ||
| + | - dacă lista conține unul sau mai multe cuvinte, face o alegere întâmplătoare și se transmite clientului; | ||
| + | - dacă lista nu conține nici un cuvânt, transmite clientului șirul de caractere //End Game// (stocat în ''Constants.END_GAME''), pentru a indica faptul că a fost închis (nu găsește nici un cuvânt cu prefixul solicitat); | ||
| + | - în caz negativ, transmite înapoi cuvântul pe care l-a primit; | ||
| + | - dacă termenul nu este valid, trimite înapoi cuvântul pe care l-a primit. | ||
| + | |||
| + | <note important>Este posibil ca un cuvânt care există în limba engleză să nu fie marcat ca valid, datorită faptului că se inspectează numai prima pagină dintre cele care conțin lista de cuvinte precedate de un anumit prefix.</note> | ||
| + | |||
| + | Similar, clientul va avea următoarea funcționare: | ||
| + | - dacă termenul din câmpul text ''wordEditText'' are mai mult de două caractere, este trimis clientului; | ||
| + | - se primește o valoare de la server: | ||
| + | - dacă se primește //End Game//, se invalidează controalele grafice, astfel încât jocul să nu poată fi continuat; | ||
| + | - dacă s-a primit alt cuvânt decât cel trimis anterior, se determină prefixul cu care trebuie format termenul și se afișează în câmpul text ''wordEditText''; | ||
| + | - dacă s-a primit același cuvânt cu cel trimis anterior, înseamnă că termenul nu a fost corect, astfel încât trebuie format un cuvânt cu același prefix ca anterior, acesta fiind afișat în câmpul text ''wordEdiTtext''; | ||
| + | - altfel, se afișează un mesaj de eroare. | ||
| + | Informațiile cu privire la șirurile de caractere care au fost trimise, respectiv primite, vor fi jurnalizate în câmpurile text ''serverHistoryTextView'' și ''clientHistoryTextView''. | ||
| - | **???.** Să se încarce modificările realizate în cadrul depozitului 'Laborator06' de pe contul Github personal, folosind un mesaj sugestiv. <code> | + | **8.** Să se încarce modificările realizate în cadrul depozitului 'Laborator06' de pe contul Github personal, folosind un mesaj sugestiv. <code> |
| - | student@pdsd2015:~/Laborator06$ git add * | + | student@eim2016:~/Laborator06$ git add * |
| - | student@pdsd2015:~/Laborator06$ git commit -m "implemented taks for laboratory 06" | + | student@eim2016:~/Laborator06$ git commit -m "implemented taks for laboratory 06" |
| - | student@pdsd2015:~/Laborator06$ git push Laborator02_perfectstudent master | + | student@eim2016:~/Laborator06$ git push Laborator02_perfectstudent master |
| </code> | </code> | ||
