domenica 31 ottobre 2010

Arduino: semaforo (versione 2)

Vi ricordate il semaforo visto ieri? Il circuito mostrato sopra ne estende le capacità aggiungendo adesso un bottone (collegato al pin 3) per l'attraversamento dei pedoni. L'interazione è come sempre gestita attraverso il software. Qui trovate il codice sorgente per l'IDE di Arduino.
Per questo sketch ho usato la libreria Metro per Arduino. All'interno del programma mi occorreva qualcosa che mi liberasse dal conteggio del tempo per dedicarmi alla gestione del bottone. La libreria Metro fa proprio questo! Qui trovate la pagina che spiega come installarla e utilizzarla all'interno dell'IDE. Fondamentalmente, una volta importato l'header (Metro.h) occorre creare una variabile per il conteggio con l'omonimo costruttore Metro(interval), dove interval è un unsigned long ed esprime l'intervallo di conteggio (in millisecondi) per la variabile dichiarata. In altre parole la variabile, appena viene dichiarata, fa scorrere il tempo fino all'intervallo di tempo impostato. Con il metodo reset() è possibile far ripartire il conteggio. Esiste un secondo costruttore che prevede come secondo argomento un valore logico che, se settato a true, fa ripartire il conteggio automaticamente.
Il metodo più importante offerto dalla libreria, a mio avviso, è il metodo check(). Questa funzione ritorna true se l'intervallo di tempo impostato nel costruttore è passato, altrimenti restituisce false. Se abbiamo bisogno di modificare l'intervallo di tempo da conteggiare va usato il metodo interval(new_interval), dove new_interval è un unsigned long che esprime (in millisecondi) il nuovo intervallo di tempo.
Dopo aver dichiarato dove sono mappati i led ed il bottone, ho dichiarato le costanti di tempo usate per le pause nel corso del programma. Ogni nuova costante di tempo per la durata di un led va quindi modificata nella parte iniziale del codice. Il programma usa due variabili globali, una per segnare lo stato del bottone e una per la presenza di pedoni. In realtà lo stato delle due variabili coincidono: se il bottone è stato premuto è evidente che ci sono pedoni! Tuttavia, per facilitare la gestione del codice ho deciso di tenere separate le due variabili, i cui stati sono gestiti in diversi istanti del ciclo di funzionamento.
La variabile Metro è dichiarata solo in una funzione (green_light()), a livello locale quindi, sicché nessun'altra funzione può interferire con il conteggio. La stessa funzione fa quindi partire il timer (variabile timer) e accende la luce verde. L'istruzione per verificare lo stato del bottone (button_stat=digitalRead(BUTTON)) è inserita in un ciclo do-while() la cui condizione di uscita è la verifica del timer con timer.check(). Tale ciclo può allora terminare per due motivi: per la fine del conteggio, per un cambiamento di stato del bottone. Quest'ultimo evento viene eventualmente segnato nella variabile globale people, in questo modo la funzione red_light() saprà se aggiungere un ulteriore tempo alla sosta delle macchine (per permettere a più pedoni di attraversare).

sabato 30 ottobre 2010

Arduino: semaforo (versione 1)

Il codice che realizza il loop per l'accensione in sequenza dei led è davvero molto semplice. Con l'istruzione digitalWrite(LED,HIGH) viene acceso un singolo led per un tempo seguito dall'istruzione delay(TIME). Passati TIME millisecondi (la funzione delay interpreta l'argomento passato in millisecondi) occorre spegnere il led acceso con digitalWrite(LED,LOW) e accendere, quindi, il led successivo. Qui trovate il file per l'IDE di Arduino.
E se qualche pedone deve attraversare?

venerdì 29 ottobre 2010

Cambiare la proprietà di un file

La regola usata sui sistemi operativi GNU/Linux dice che colui che crea il file ne è anche il proprietario. Con il comando chown è possibile assegnare la proprietà del file a un altro utente, basta passare come argomento il nome dell'utente (oppure il suo ID numerico, che può essere trovato nel file /etc/passwd, provate a leggerne il contenuto con less /etc/passwd). Ad esempio, con il comando chown new_user file.txt l'utente che possiede la paternità del file file.txt (e che può dunque eseguire il comando) la sposta a favore dell'utente new_user.
Il comando chown permette di cambiare, oltre al proprietario, anche il gruppo di appartenenza del file. Per fare ciò basta far seguire al nome del nuovo proprietario il nome del nuovo gruppo, separato dal precedente dal carattere :.

Avete osservato bene l'immagine sopra? Se lo avete fatto avete allora capito che il comando chown può essere lanciato, oltre che dal proprietario del file, anche dall'utente root! L'utente root può fare tutto, ricordatelo sempre! La stringa sudo anteposta al comando sta a significare super user do. Pertanto, un comando preceduto da sudo verrà eseguito con i privilegi dell'utente root

giovedì 28 ottobre 2010

Cambiare i permessi a un file

Per ogni file e per ogni gruppo di utenti sono possibili tre tipologie di permessi che di seguito elenco: lettura (r, read), scrittura (w, write) ed esecuzione (x, executable). La stringa rwx viene riportata in corrispondenza dei gruppi di utenti per l'assegnazione dei permessi. In assenza di uno dei permessi il carattere - prende il posto del permesso negato.

I gruppi di utenti previsti per l'utilizzo del file prevedono: l'utente proprietario del file (user), il gruppo a cui appartiene l'utente (group) e il gruppo formato da tutti gli altri utenti (other). I permessi per i file dicono chiaramente chi può fare cosa e chmod (eseguito dal proprietario o dall'utente root) è il comando che li modifica.

Con chmod possiamo assegnare e rimuovere permessi. L'assegnazione avviene facendo precedere ai simboli che descrivono i permessi (r,w oppure x) il simbolo +. La rimozione di un permesso prevede invece l'uso del simbolo -. Bene, non ci rimane che capire come fare per indicare al comando chmod verso quale gruppo direzionare i nuovi permessi. Ricordate la precedente distinzione fatta sui gruppi? I gruppi user, group e other vengono referenziati dal comando chmod, rispettivamente, dai simboli u,g ed o.

Questo significa che se voglio aggiungere ai gruppi group (g) e other (o) i permessi in lettura e scrittura, verso il file file.txt, scriverò qualcosa del genere: chmod go+rw file.txt! Analogamente, se decido che i precedenti due gruppi possono leggere il file.txt senza modificarne i contenuti, scriverò qualcosa di questo tipo: chmod go-w file.txt!

Non sempre, però, i gruppi di utenti vantano gli stessi permessi nei confronti di un file! Questo significa che, in alcune circostanze, bisogna chiamare chmod più volte. In realtà il comando permette l'assegnazione dei permessi anche attraverso una seconda notazione, detta numerica. La prima notazione vista e usata da chmod viene detta alfabetica.

Nella notazione numerica viene passato al comando un numero, composto da tre cifre, che sintetizza i permessi da assegnare ai vari gruppi. Ogni singola cifra viene ottenuta sommando i pesi attribuiti ai vari permessi: r vale 4, w vale 2 ed x vale 1. Pertanto, se un gruppo ha i permessi in lettura (4) e scrittura (2), il numero da passare a chmod, in corrispondenza del gruppo è 6! Il primo numero passato a chmod è assegnato all'utente (user, il proprietario del file), il secondo numero specifica i permessi assegnati al gruppo group e l'ultimo indica i permessi per il gruppo other. Ad esempio, con il comando chmod 644 file.txt vengono assegnati al file file.txt i permessi di lettura e scrittura per l'utente, quello di sola lettura per i gruppi group e other

mercoledì 27 ottobre 2010

I permessi per file

La gestione dei permessi nei sistemi operativi GNU/Linux è sempre stata precisa, fin dalle prime versioni. Se eseguiamo il comando ls -l riceviamo un elenco lungo dei file, contenente anche i permessi degli stessi.


Cosa sono quelle stringhe all'inizio di ogni riga?

La sequenza formata dai primi 10 caratteri esprime la tipologia di permessi associata al file! Il primo carattere, se presente, indica se la riga si riferisce a un file oppure a una directory. In quest'ultimo caso sarà presente il carattere d, altrimenti il simbolo -. I restanti 9 caratteri vanno interpretati in 3 gruppi di 3 caratteri. Ognuno di questi 3 caratteri prevede la sequenza di simboli rwx, rispettivamente per il permesso in lettura (r, read), scrittura (w, write) ed esecuzione (x, execute). Se uno di questi permessi è assente sarà presente il carattere -. Attenzione, per una directory il permesso x indica la possibilità di entrare nella stessa!

Il primo gruppo di caratteri rwx (se presenti) rappresentano i permessi assegnati all'utente che crea il file, il proprietario del file. Il secondo gruppo di caratteri rwx è invece assegnato al gruppo a cui appertiene il proprietario del file (Linux è un sistema operativo multi-utente, ogni utente può appartenere a un gruppo di utenti e ogni gruppo di utenti può vantare nei confronti di file e directory i dovuti permessi). Il terzo gruppo di caratteri rwx, infine, rappresentano il permessi assegnati agli altri utenti.

Se osserviamo l'output dello screen shot mostrato sopra possiamo adesso comprendere che acer (la prima voce dell'elenco) è una directory (accessibile, ha il permesso x!) e che la maggior parte dei file è accessibile dall'utente proprietario in lettura e scrittura (rw-), dal gruppo del proprietario in sola lettura (r--) e dagli altri utenti, infine, in sola lettura (r--).

martedì 26 ottobre 2010

Leggere i file

Se ci occorre leggere il contenuto dei file di testo, ad esempio quelli di configurazione usati dal sistema operativo, abbiamo a disposizione più di un comando! Il comando cat è uno dei primi comandi scritti per Linux che permette la visualizzazione del file all'interno della finestra del terminale. La sintassi da usare prevede come argomento da passare al comando il nome del file da visualizzare. Ad esempio, il comando: cat /etc/modules ci mostra il contenuto del file modules nella cartella /etc (si tratta di un file usato dall'utente per segnalare al sistema operativo i moduli da caricare, al di fuori di quelli caricati di default, in fase di avvio).

Questa è la schermata ritornata dall'esecuzione del comando cat /home/light-kun/Scaricati/acer/aspireone/110/L/caratteristiche.txt:


Qui si nota una forte limitazione del comando cat! Se il testo da mostrare nel terminale è molto siamo costretti a risalire verso l'alto, facendo operazioni di scrolling. Il comando cat riversa nella finestra del terminale tutte le righe del documento da leggere, cosa non sempre comoda. Esistono, come dicevo all'inizio, altre alternative. Prima di vederle vorrei però completare il discorso su cat dicendovi un ultima cosa. Il comando cat nasce inizialmente come concatenatore di file. Con cat file1 file2 > file3 concateniamo i primi due file (file1 e file2) in un terzo file (file3). Se al comando viene passato un solo argomento ne viene allora visualizzato il contenuto.
Qualche volta può capitare, se usate cat, che il terminale venga inondato di testo e che il prompt vi venga restituito non prima che cat stampi tutte le righe. Il comando less è particolarmente utile nella lettura dei file, soprattutto se questi sono lunghi. less, infatti, ne stampa il contenuto una schermata alla volta. La visione del testo procede alla schermata successiva, oppure a quella precedente, attraverso i tasti Pagina su e Pagina giù. Con i tasti Freccia su e Freccia giù si sposta il testo, rispettivamente, al rigo successivo e precedende. Con il tasto Q (quit) si chiude il programma.

Vi occorre cercare una parola all'interno del file che state visualizzando? Nessun problema, con il visualizzatore in esecuzione nel terminale premete il tasto /, scrivete la parola da cercare e premete su Invio. Se la parola che avete scritto viene trovata nel documento la visualizzazione di quest'ultimo inizierà a partire dalla riga che contine la prima occorrenza della parola trovata! Con n ripetete la ricerca passando all'occorrenza successiva, con N tornate sull'occorrenza precedente. Cosa ne pensate?
Altri comandi utili alla visualizzazione di file sono more (less ne è un estensione, i due comandi si somigliano molto), tail (mostra le ultime righe del documento) ed head (mostra le prime righe del documento).

lunedì 25 ottobre 2010

Xubuntu 10.10, prova su Aspire One

Per la prova dell'ultima versione di Xubuntu (la 10.10) ho avuto dei problemi nella creazione della pen-drive usb, poi risolti usando l'ultima versione di Unetbootin. L'immagine del sistema operativo, disponibile presso il sito di riferimento della distribuzione, occupa circa 680MB.

L'avvio è stato piuttosto lungo, occorrono poco più di 90 secondi (di sicuro l'esecuzione da disco fisso impiega meno tempo), che vanno dall'accensione dell'Aspire One fino alla comparsa del desktop.

Ho quindi provato i due lettori di schede di memorie, stesso esito anche qui: il lettore a sinistra dellAspire One funziona, quello a destra invece no. Noto subito, come si può notare dall'immagine del desktop mostrata sopra, che il volume è assente! Durante la prova ho risolto questo problema cliccando il tasto destro del mouse sull'icona del volume, nel pannello in alto. Ho poi selezionato la voce "Properties" e in corrispondenza dell'etichetta "Sound card" ho selezionato "PulseAudio Mixer". Cambiando il volume, attraverso la nota combinazione di tasti, ho quindi verificato che tutto, adesso, andava bene.

Un ulteriore prova è poi avvenuta effettuando la connessione ad Internet attraverso il mio router, la scheda wifi viene quindi riconosciuta dal sistema operativo senza alcun intervento. Durante la navigazione in Internet, dopo aver installato l'opportuno plugin, ho quindi verificato sia l'audio (è ok, si sente) che la fluidità dei video (non proprio fluidi, meglio un altro browser?).

Aggiunto un nuovo task manager, in stile Xfce. In condizioni di riposo l'uso della memoria ram è del 35%, 182MB su 512MB disponibili, attenzione a questi 182MB vanno tolti quelli condivisi con la scheda video. In ogni caso, rimangono a disposizione dei processi utente circa 330MB (il restante 65%).

Questa versione non mi ha colpito particolarmente, consapevole anche dell'esecuzione su pen-drive usb. Forse perché già da alcune versioni le prestazioni di quesa distribuzione sull'Aspire One si sono ormai assestate. Va comunque detto che anche questa distribuzione ottimizza l'uso della memoria ram ed è meno impegnativa per la cpu rispetto alla versione classica di Ubuntu con Gnome. Con Xubuntu e Lubuntu possiamo portare Ubuntu sull'Aspire One (110). Personalmente ho apprezzato molto l'impegno del team di Xfce di sostituire i programmi legati all'ambiente Gnome (che solitamente si portano dietro le librerie di programmi necessaie all'esecuzione del programma) con quelli dedicati appositamente per Xfce (come è stato fatto in Lubuntu). Fra le novità di questa versione troviamo:

  • Parole, il nuovo player di file multimediali di Xfce4;
  • Xfburn, che sostituisce Brasero come programma di scrittura su supporti CD/DVD;
  • Xfce4-taskmanager (visibile nell'ultimo screen shot), un task manager che usa meno risorse rispetto a Gnome-Task-Manager (presente, invece, nelle precedenti versioni);
  • Le ultime versioni di Gnumeric e Abiword;
  • Un nuovo tema grafico, bluebird;

Spostare file e directory

A volte desideriamo spostare un file oppure una cartella (intera) piuttosto che tenerne più copie sul file system. In tal caso, anzichè usare cp, occorre usare il comando mv (move). Con mv possiamo spostare file e directory da un punto a un'altro del file system. La sintassi è davvero molto semplice: mv sorgente destinazione, dove sorgente è il path al file o alla cartella da cui prendere l'input e destinazione è il path al file o cartella in cui scrivere l'output.

Il comando mv ci permette anche di rinominare file e cartelle se ad esempio passiamo come argomento di destinazione lo stesso path del sorgente, con nome finale (del file o cartella) diverso. Ad esempio, con il comando: mv /home/user/Downloads/immagine1.jpg /home/user/Downloads/wallpaper1.jpg rinomina il file da immagine1.jpg a wallpaper1.jpg.

venerdì 22 ottobre 2010

Copiare file e directory

La copia dei file, assieme ai comandi ls e cd, è una delle operazioni più eseguite in un terminale Linux. Il comando cp permette di copiare file e cartelle, la sintassi da usare è la seguente: cp sorgente destinazione, dove sorgente è il nome del file da cui copiare mentre destinazione è il nome del file in cui scrivere la copia. Gli argomenti sorgente e destinazione passati al comando cp possono essere path assoluti o relativi. Attenzione, se copiate un file nella stessa cartella di destinazione assicuratevi di usare un nome diverso dal file originale altrimenti il processo di copia non avrà inizio. Se la destinazione del file copiato è invece diversa dalla sorgente potete allora mantenere il nome originale del file.

Con il carattere jolly * possiamo copiare più file. Ad esempio, con il comando cp /home/user/Downloads/mp3/*.mp3 /media/pendriveusb/Musica/ indico al terminale di Linux di copiare tutti i file mp3 nell'omonima cartella (ho usato un path assoluto, a partire dalla directory radice) nella cartella Musica presente sulla pen-drive usb (montata al file system in /media/pendriveusb).

Il comando cp sovrascive i file da copiare sui file già presenti nel path di destinazione, se questi già esistono. Nessun messaggio viene inviato all'utente sulla presenza di file con lo stesso nome! Se vogliamo essere avvertiti da questa eventualità va allora usato il comando cp con l'argomento -i (interactive). Solo in questo caso il terminale ci avverte della presenza di file che stanno per essere sovrascritti. Saremo noi a decidere se continuare o lasciar perdere la copia.

Per copiare un'intera directory va usato il comando cp con l'argomento -R (recursive). Solo in questo modo verranno copiate sia le directory che i file. Ad esempio, il comando: cp -R /home/user/Downloads/mp3/ /media/pendriveusb/Musica/ copia la cartella mp3 con tutti i file presenti all'interno nella cartella Musica della pen-drive usb.

giovedì 21 ottobre 2010

Cancellare file e directory

Il comando per cancellare file e cartelle in Linux è rm (remove). In realtà rm cancella esclusivamente file, per le directory si dovrebbe utilizzare il comando rmdir (remove directory). Una forte limitazione di rmdir è la seguente: il comando cancella solo le directory vuote! Con rm, passando al comado gli argomenti giusti, si può allora superare la limitazione di rmdir.

Procediamo con ordine e occupiamoci dei file. La sintassi usata da rm è la seguente: rm nome_file, dove nome_file è il nome del file da cancellare. La rimozione del file riesce se e solo se l'utente che lancia il comando ha i permessi per farlo! L'argomento nome_file passato ad rm può essere un path sia assoluto che ralativo e, cosa più importante, può prevedere l'uso del carattere jolly *. Il carattere jolly ci permette di individuare e cancellare in un colpo solo più tipologie di file. Ad esempio, con il comando: rm *.jpg dico al terminale di Linux di cancellare tutti i file con estensione jpg (immagini) presenti nella directory di lavoro.

A differenza dell'interfaccia grafica che, se usata per cancellare file, sposta i file cancellati nel cestino, il comando rm elimina i file dal file system senza possibilità di recupero. rm non ha un cestino! Un file cancellato con rm può essere recuperato solo attraverso particolari software e sotto precise condizioni: i settori del disco precedentemente occupati dal file cancellato non devono essere sovrascritti da nuovi file. Prestate, allora, molta attenzione nell'uso di rm, soprattutto se state usando il terminale con i permessi dell'utente root!

Una delle opzioni di rm utili proprio ad evitare la cancellazione di file importanti è l'opzione -i (interactive). Con rm -i nome_file il terminale svolge il comando in maniera interattiva, ogni operazione di cancellazione è preceduta da una domanda di conferma.

Talvolta, quando il nome del file da cancellare contiene spazi vuoti, è utile racchiudere con le virgolette l'argomento nome_file passato al comando rm, ecco un esempio: rm "nome file". Senza questa precauzione il comando rm interpreta gli argomenti passati (in questo caso il nome del file) in modo errato. rm cercherà di cancellare i file nome e file!

E per le directory? Se rmdir si rifiuta di cancellarle, se non vuote, come fare? La soluzione al problema è l'uso del comando rm con gli argomenti -Rf, dove R (recursive) dice ad rm di cancellare ricorsivamente tutte le directory contenute mentre f (force) dice ad rm di eseguire il comando senza far storie (senza questa opzione il comando vi dirà che le cartelle non sono vuote!). Pertanto, con: rm -Rf /home/user/Downloads/mp3/ cancellerò la cartella (e tutti i file contenuti) mp3!

Vediamo se avete capito, cosa fa il comando: rm -Rf /* ?

Il comando mostrato sopra, se eseguito dall'utente root, cancella tutte le directory del file systeme! Ad rm viene passato come argomento la directory radice e il carattere jolly! Fate molta attenzione a quello che scrivete!


mercoledì 20 ottobre 2010

Creare nuove directory e file

Fa sempre comodo poter organizzare i propri file e documenti all'interno di nuove directory. Il comando mkdir (make directory) ci permette di fare proprio questo, la sintassi da usare è mkdir directory, dove directory è il nome della cartella. A volte però desideriamo strutturare in maniera più articolata le nostre cartelle e creare una cartella in un'altra. Potrebbe essere noioso creare una directory, entrarci dentro con cd, e creare quindi una nuova directory lì (oppure iterare il processo più volte). Per risolvere la questione con un unico comando possiamo allora passare a mkdir l'opzione -p (parents) e specificare in directory l'intero set di directory.Il comando mkdir genererà tutte le cartelle fino al nuovo path aggiunto al file system.
In genere disponiamo i documenti creati con i nostri editor preferiti nelle cartelle del file system per poter poi accedere agli stessi, in lettura o scrittura, in un secondo momento. Possiamo creare nuovi file attraverso il comando touch, la sintassi da seguire è touch nome_file, dove nome_file è il nome da assegnare al file. Attenzione, touch crea un file vuoto, da aprire quindi con il nostro editor. Se a touch passiamo come argomento il nome di un file esistente il comando ne modificherà l'ora di accesso.

martedì 19 ottobre 2010

Elenchi di file e cartelle

L'avvio della finestra del terminale fa puntare di default la directory di lavoro nella home dell'utente. Il prompt del terminale ne sintetizza il path con il simbolo ~ (che identifica la directory /home/nome_utente/). Quest'ultimo si presenta nella forma: nome_utente@nome_computer:directory_di_lavoro$. La directory di lavoro è la posizione occupata lungo l'albero che rappresenta il file system. Il prompt della mia console Linux (il terminale di Linux è anche chiamato in questo modo) è ad esempio: light-kun@ryuk:~$. Con il comando pwd (print work directory) posso conoscere in ogni momento il path completo della directory di lavoro corrente. pwd è il nostro navigatore, ci dice dove ci troviamo!
light-kun@ryuk:~$ pwd
/home/light-kun
light-kun@ryuk:~$
Uno dei comandi più utilizzati è senza dubbio il comando ls (list) che elenca i file e le cartelle presenti nella directory di lavoro. In realtà non occorre trovarsi in una directory per poter ricevere l'elenco dei file e delle cartelle in essa contenute se al comando ls si fa seguire il path della directory!
light-kun@ryuk:~$ ls ./Scaricati/
Java, mattone dopo mattone.pdf
light-kun@ryuk:~$
Il comando ls accetta  un'infinità di opzioni. Se siamo interessati all'elenco di un certo tipo di file possiamo ricorrere al carattere jolly *, ad esempio, con: ls *.png chiediamo la lista di tutti i file, se presenti, con estensione png. Alcuni file sono nascosti e il semplice comando ls non ne provoca la stampa a video! Con l'opzione -a (all) provochiamo anche la stampa, nell'elenco di output, dei file nascoti. Un file è caratterizzato da permessi, da una dimensione, dalla data di creazione e da quella di accesso. Con l'opzione -l (long) possiamo ricevere un elenco assai dettagliato dei file. La dimensione dei file è espressa in byte (unità di misura troppo piccola), con l'opzione -h (human readable) tale valore ci viene restituito con i suffissi K, M e G assegnati rispettivamente ai Kilobyte, Megabyte e Gigabyte. Le opzioni di ls sono ancora molte, vi consiglio di accere alla pagina del manuale che descrive il comando (ogni comando ha una pagina nel manuale) digitando nel terminale man ls. Vi ricordo che è possibile combinare le opzioni! Ad esempio, con il comando ls -lh chiediamo al terminale la stampa di una lista lunga dei file presenti nella directory di lavoro, con valori leggibili per le dimensioni impegnate da ciascun file.

Avete osservato bene l'immagine sopra? Prima di eseguire il comando ls -lh ho eseguito il comando cd Scaricati/. Il comando cd (change directory) serve a cambiare la directory di lavoro. Se con ls riceviamo la lista dei file e delle directory, con cd, allora, possiamo spostarci in una nuova directory. La sintassi prevista dal comando è cd directory, dove directoy può essere un path relativo (ad esempio a partire dalla directory corrente e quindi con il simbolo ./ oppure a partire dalla directory padre e quindi con il simbolo ../) o assoluto (se il path inizia dalla radice e quindi con il simbolo /). Se a cd non viene indicato nessun path verso una nuova directory il comando sposta la directory di lavoro nella home dell'utente. Infine, se dopo aver spostato la directory di lavoro desideriamo tornare indietro possiamo farlo con il comando cd -.

lunedì 18 ottobre 2010

Lubuntu 10.10, prova su Aspire One

Quasi in concomitanza con l'uscita  di Ubuntu 10.10, Maverick Meerkat, è stata rilasciata la nuova versione di Lubuntu. Ho subito provato l'ultima versione scaricando l'immagine del sistema operativo dal sito di riferimento della distribuzione, un file .iso grande circa 545MB, sul mio Aspire One (il 110L, con SSD da 8GB e memoria ram di 512MB). La live da eseguire con la pen-drive usb è stata come al solito creata con Unetbootin.

Durante l'avvio del sistema operativo si verificano dei messaggi di errori che non ne interrompono il caricamento. L'Aspire One ha impiegato circa 65 secondi (incluso il tempo per necessarrio a selezionare, attraverso il tasto "F12" l'avvio dalla pen-drive usb). La versione del kernel Linux usata da Lubuntu 10.10 è 2.6.35-22. 

La scheda di rete viene riconosciuta correttamente, l'accesso al router e la navigazione in Internet riesce senza problemi. Il led della scheda di rete funziona al passaggio del traffico di rete, altre volte sembra rimanere fisso. Così come in molte distribuzioni GNU/Linux, anche in Lubuntu 10.10 il lettore di schede alla destra dell'Aspire One non sembra funzionare. Nessun problema per quello a sinistra. In questa versione le combinazioni di tasti con il tasto "Fn" funzionano correttamente (nella precedente versione non andavano). E' possibile regolare sia l'audio che la luminosità, tuttavia nessuna notifica sembra comparire (potrebbe essere utile almeno per l'audio). In questo modo si viene a creare una discrepanza di valori nel caso del volume: la barra disposta nel pannello per la regolazione del volume si discosta dal reale valore se quest'ultimo è stato ritoccato attraverso la combinazione di tasti. I dispositivi di memoria collegati all'Aspire One vengono montati automaticamente. Il layout della tastiera non corrisponde al mio modello, magari nell'installazione sul disco questo difetto sparisce (o va eventualmente corretto). La webcam viene riconosciuta e utilizzata da Cheese.

La distribuzione si comporta, così come la precedente versione, davvero molto bene. La navigazione è piacevole con Chromium web browser. Il sistema risponde bene ai comandi, senza mai esitare. In questa versione sono stati aggiunti nuovi software, ora Lubuntu dispone di un proprio gestore di processi, LXTask, e di Xpad. Altri programmi sono stati invece rimossi, come Parcellite e pyNeighborhood. Evince è il nuove lettore di file PDF! Nel menu sono adesso presente dei giochi. E' stato infine aggiornato il sistema di notifiche (abilitato adesso anche agli aggiornamenti tipici di Ubuntu).

Sono un po rimasto perplesso quando il task manager mi mostrava la memoria ram usata dal sistema operativo:

Adesso (in condizioni di riposo) la memoria ram utilizzata  è di 168MB su 484MB disponibili. Nella precedente versione l'utilizzo della memoria ram (nelle stesse condizioni) lasciava più spazio ai processi dell'utente! Personalmente preferisco la versione 10.04 di Lubuntu proprio per questo motivo, poiché meglio realizza gli obiettivi della distribuzione (e anche una mia esigenza). Badate bene, il sistema operativo mantiene (almeno da live) gli stessi tempi della precedente versione e va in ogni caso presa in considerazione per il nostro Aspire One.

sabato 16 ottobre 2010

Linux: il file system

Il passaggio a un nuovo sistema operativo è sempre accompagnato, per la maggior parte degli utenti (nuovi), da una sensazione di disorientamento. Questa è la cosa che molte volte mi capita di riscontrare. Se la soluzione a qualche problema era prima a portata di mano e veniva quindi tentata, adesso con GNU/Linux (è questo il modo corretto per indicare il sistema operativo) ci si sente disorientati. Le domande tipiche sono: "come faccio a fare questo?", "cos'è questo file?", "a cosa serve questo?", "dove trovo questo?", etc...

Bisogna sfruttare, fin dall'inizio, il nostro entusiasmo per apprendere l'uso del nuovo sistema operativo GNU/Linux. Il tempo speso in questa fase di apprendimento sarà ben ricompensato quando di fronte a un problema sapremo come e cosa fare! Prima ancora di iniziare a impartire comandi dal terminale è utile conoscere l'organizzazione del file system usato nei sistemi operativi GNU/Linux. Questo chiarirà alcuni concetti che ritengo necessari e toglierà (lo spero) una buona parte di quella sensazione di disorientamento che dicevo all'inizio.

Ogni sistema operativo realizza sul nostro computer un livello di astrazione per permettere l'uso dell'hardware sottostante. Il nostro hard disk, ad esempio, senza questo livello di astrazione risulterebbe scomodo da utilizzare, quasi impossibile! L'astrazione necessaria al nostro hard disk, lo sappiamo bene, è il concetto di file e cartelle. E' grazie a questi due concetti che possiamo organizzare i nostri documenti!

Un file fa dunque da contenitore per i nostri dati: musica, video, immagini, testo etc... Ogni file ha un nome, lungo al massimo 256 caratteri. Per il nome possiamo usare tutti i caratteri dell'alfabeto, i numeri, i simboli di punteggiatura e sottolineatura. Sono invece vietati alcuni caratteri speciali come il punto interrogativo, lo spazio e l'asterisco. Questa limitazione verrà chiarita negli articoli successivi. Una cartella, invece, fa da contenitore per i file. In Linux i nomi di file e cartelle sono case sensitive. Cosa significa questo? Per il sistema operativo i nomi "nome_file" e "NOME_FILE" individuano due file distinti! Il sistema operativo distingue i caratteri scritti in maiuscolo da quelli scritti in minuscolo contrariamente a quanto avviene invece sotto i sistemi operativi Windows.

Mentre l'organizzazione dei documenti è lasciata all'utente, ogni utente dispone di un propria cartella detta anche home dell'utente (che assume in molti casi proprio il nome dell'utente), la gestione dei file e delle cartelle di sistema è per ovvi motivi lasciata al sistema operativo. Come organizza i file un sistema operativo GNU/Linux?

Il file system di un sistema GNU/Linux definisce una cartella, detta directory principale o radice, per raccogliere in seguito tutti i file e le cartelle. La directory principale è identificata dal seguente simbolo: /.  La struttura di un file system ricorda quella di un albero (capovolto), la directory principale è per questo motivo detta anche directory radice!

La directory principale è dunque un contenitore per altre cartelle e file. Per l'accesso a una cartella o file è indispensabile fornire un indirizzo che indica il percorso all'interno dell'albero. Tale percorso può essere assoluto se l'indirizzo inizia dalla directory principale, oppure relativo se l'indirizzo inizia a partire da una certa cartella (la directory di lavoro corrente, come vedremo in seguito). Per separare i nomi delle directory che compongono un percorso si usa ancora una volta il carattere / (che non può essere confuso con la directory principale, il cui simbolo può solo trovarsi all'inizio di un indirizzo). Pertanto, l'indirizzo /usr/bin/ identifica la cartella bin che si trova nella cartella usr che a sua volta si trova nella cartella principale /.

Nei file system usati dai sistemi operativi GNU/Linux (e in generale nei sistemi operativi Linux-like) troviamo in ogni cartella due cartelle particolare (anche se la cartella è vuota!). Si tratta in realtà dei collegamenti alla directory corrente e alla directory padre (quella che fa da contenitore alla directory corrente). La presenza di queste due cartelle è particolarmente utile per effettuare spostamenti all'interno del file system. Il collegamento alla directory corrente è individuato dal simbolo ./ mentre quello alla directory padre dal simbolo ../. Se ad esempio mi trovo nella cartella /usr/bin/ con l'indirizzo ../ intendo referenziare la directory padre e quindi la directory /usr/. Esiste poi una notazione per indicare in maniera compatta la directory dell'utente (che potrebbe essere ad esempio /home/nome_utente/) attraverso il simbolo ~.

Come dicevo poco fa il sistema operativo realizza sul file system una struttura di cartelle per l'allocazione dei file sul disco. Tale struttura può variare leggermente in ogni sistema operativo GNU/Linux (distribuzioni), in generale essa prevede all'interno della directroy principale le seguenti cartelle: bin, boot, dev, etc, home, lib, lost+found, mnt, proc, opt, root, sbin, tmp, usr e var. Vediamo come...:

  • bin: in questa cartella si trovano i file e i collegamenti ai comandi (non tutti) che solitamente invochiamo dalla riga del terminale;
  • boot: qui troviamo i file usati per l'avvio del sistema operativo, come il file vmlinuz, il kernel compresso (il nome del file è solitamente seguito dal numero di versione del kernel usato). All'interno di questa cartella troviamo anche la cartella usata dal boot loader (come Grub) il programma che avvia il sistema operativo (sotto directory /boot/grub/). Se cercate i file che configurano il boot loader date uno sguardo qui, oppure nel file /etc/grub.conf;
  • dev: in GNU/Linux ogni periferica o dispositivo è visto come su file, qui trovate i file collegati alle periferiche;
  • etc: in questa cartella si trovano i file di configurazione dei programmi (ogni programma potrebbe avere in questa cartella una propia cartella, con il nome del programma, come ad esempio la cartella /etc/firefox/). All'interno troviamo numerose sotto directory! Se il nostro sistema operativo usa il gestore di pacchetti APT (Advanced Packaging Tool) troveremo allora la cartella /etc/apt/ con all'interno i file source.list con gli indirizzi dei server usati per il prelievo dei pacchetti software dalla rete (i famosi repository, ne parleremo in seguito). Il file /etc/fstab contiene la tabella dei file system e indica i dispositivi che devono essere montati (con le eventuali opzioni) all'avvio. La cartella /etc/init.d/ contiene gli script da eseguire all'avvio e nel file /etc/modules sono elencati i moduli (il kernel del sistema operativo è modulare e all'occorrenza possono essere aggiunti pezzi di codice, i moduli, per la gestione di periferiche);
  • home: in questa cartella viene solitamente creata una cartella per ogni utente (detta cartella di home dell'utente) abilitato all'uso del computer. Il nome della cartella coincide con il nome dell'utente. Molte applicazioni salvano qui, in file e cartelle nascoste, la configurazione usata dall'utente! Nella maggior parte dei casi questi file non sono visibili attraverso il gestore grafico dei file, il cosiddetto file manager. Occorre infatti abilitare la visualizzazione di tali file (nascosti) oppure interrogare il sistema operativo attraverso il terminale con un opportuno comando (che vedremo in seguito);
  • lib: raccoglie file di librerie di programmi. In questo modo più programmi possono condividere la stessa libreria;
  • lost+found: se per qualche motivo il disco perde qualche file o cartella (ad esempio perché il sistema operativo non viene spento bene) in questa cartella troviamo i file recuperati, all'avvio, dal sistema operativo;
  • mnt: ogni periferica dotata di un proprio file system, lettori cd-rom e/o dvd, pen-drive usb e schede di memorie vengono attaccate (operazione di mount) al file system del computer in questa cartella (oppure nella cartella /media/);
  • proc: ogni programma in esecuzione su un sistema GNU/Linux è identificato da un codice (PID, Process ID), in questa cartella sono tenute le informazioni sui processi in esecuzione. Ad ogni processo in esecuzione viene assegnata una cartella (il cui nome corrisponde al PID), all'interno di questa ogni file raccoglie informazioni sul processo: l'attuale stato, la memoria utilizzata, la percentuale di processore impegnata etc... Tranquilli, quando siamo a caccia di queste informazioni non è necessario fare una ricerca in questa cartella, esistono dei precisi comandi che svolgono questo lavoro e rendono quindi visibile l'output (sia su terminale che in una interfaccia grafica).  All'interno della cartella /proc/ prendono posto anche alcuni file con le informazioni sul sistema;
  • opt: questa cartella viene usata (non sempre) dal sistema operativo per installare il software aggiunto dall'utente attraverso il gestore di pacchetti;
  • root: è la directory home dell'utente root, l'amministratore del computer;
  • sbin: raccoglie tutti i comandi e gli script eseguibili solo dall'utente root;
  • tmp: raccoglie tutti i file temporanei. Alcune distribuzioni puliscono questa cartella all'avvio del sistema operativo, altre invece effettuano una pulizia solo ciclicamente. Il mio consiglio è quello di lasciare al sistema operativo la gestione di questa cartella;
  • usr: raccoglie i programmi installati e messi a disposizione dell'utente. In /usr/bin/ si trovano i file dei comandi a disposizione dell'utente. Nelle cartelle /usr/man/ e /usr/doc/ vengono allocate rispettivamente le pagine del manuale (comando man) e la documentazione del software. Particolarmente popolata è la cartella /usr/share/, dove ogni software installato ha una propria cartella;
  • var: contiene file il cui contenuto varia durante l'esecuzione del sistema operativo. Raccoglie i pacchetti scaricati e installati attraverso il gestore di pacchetti nella cartella /var/cache (ad esempio nella cartella /var/cache/apt/);

Vi invito a verificare personalmente la struttura del vostro file system attraverso il file manager della vostra distribuzione! Nei prossimi articoli ci occuperemo dei comandi per il terminale, conoscerli e capirli non può che essere un bene.

venerdì 15 ottobre 2010

Lubuntu 10.04, prova su Aspire One

Lubuntu è un sistema operativo GNU/Linux derivato da Ubuntu, la prima release risale a maggio 2010 (derivata da Ubuntu 10.04, Lucid Lynx). Il window manager utilizzato è Openbox, particolarmente leggero e adatto a dispositivi con poche risorse. Trovate altre notizie sulla homepage ufficiale della distribuzione. Perché non provarlo sull'Aspire One 110L?

La versione provata è stata la 10.04, ho scaricato l'immagine del sistema operativo (un file .iso di circa 520MB) e creato la pen-drive attraverso Unetbootin. Come dicevo all'inizio il window manager utilizzato è Openbox, il desktop environment è invece LXDE (Lightweight X11 Desktop Environment), da cui deriva appunto il nome dato alla distribuzione.

L'avvio ha richiesto, a partire dall'accensione, circa 70 secondi. Il tempo effettivamente utile all'avvio è pertanto minore se a quest'ultimo si sottrae infatti il tempo impiegato per selezionare la pen-drive usb in fase di avvio con il tasto F12. Va poi considerata la bontà della periferica esterna utilizzata, nel mio caso una pen-drive usb di 4GB prodotta da Kingston. Prestazioni maggiori si ottengono installando il sistema operativo sul disco fisso. La versione 10.04 di Lubuntu è basata sul kernel Linux 2.6.32-21. Lubuntu è una distribuzione minimale, il desktop offerto all'utente all'avvio ne fa intuire sicuramente le scelte:

Il software installato di default segue la politica che sta alla base della distribuzione, non impiegare troppa memoria ram nell'esecuzione dei processi. Nel menu delle applicazioni disponiamo (vi elenco i programmi più importanti): del file manager, PCMan File Manager (la versione 0.9.5); Image Viewer, un visualizzatore di immagini; mPaint graphic editor, un editor di immagini; Chromium web brower, un browser per Internet; Pidgin Internet messenger, per la messaggistica istantanea; Abiword e Gnumeric rispettivamente per editare file di testo e fogli elettronici; Aqualung e Gnome MPlayer per i file audio.

La memoria ram usata è davvero poca, nel mio caso 97MB su 485MB disponibili, come mostra il tool xfce4-taskmanager:

Il sistema operativo si presenta reattivo ai click dell'utente, durante la prova da me effettuata non sembrava di eseguire il sistema operativo da pen-drive usb! Vediamo nello specifico cosa funziona: il lettore di schede a destra dell'Aspire One non sembra funzionare (problema noto anche in altre distribuzioni Ubuntu), nessun problema per il lettore a sinistra che ha quindi letto il contenuto della scheda SD da me inserita. Le pen-drive usb inserite vengono montate automaticamente, l'audio viene riprodotto bene. Non ho avuto modo di provare il microfono. La webcam viene riconosciuta da Cheese che ne mostra correttamente l'output su video (con poca luce, si può rimediare nelle impostazioni). La scheda wifi viene riconosciuta e l'accesso al mio router avviene senza problemi. La potenza del segnale è stata del 55% (la distanza dal mio router è di circa 9 metri). Il modulo usato per la scheda wifi è l'ath5k per schede Atheros della serie 5xxx. La connessione di rete riesce anche attraverso il cavo ethernet. La ventola di raffreddamento è gestita dal modulo acerhdf. Non funzionano i tasti combinati, le combinazioni di tasti con il tasto "Fn" per intenderci. Il volume può essere aggiustato dal pannello inferiore ma come fare per la luminosità dello schermo? Nessuna notifica viene mostrata all'utente se la scheda wifi viene disabilitata attraverso l'apposito tasto. Dopo averlo toccato, disabilitando la schede di rete, la connessione è caduta dopo qualche secondo. L'interruttore, quindi, funziona ma lo stato non viene notificato (un problema noto anche su altre distribuzioni)!

Questa prova è stata effettuata su un Aspire One 110L, con SSD da 8GB e 512MB di memoria ram. Questa distribuzione è davvero ottima per il mio modello, l'hardware è ormai supportato a dovere dal kernel di Linux e la poca memoria ram richiesta dal sistema operativo nonché il basso utilizzo della cpu permette di avere un sistema operativo sempre pronto e reattivo alla risposta. Il sistema operativo si lascia piacere proprio per le caratteristiche dette poco fa (obiettivo, quindi, raggiunto dalla distribuzione), dall'altro lato bisogna però accettare il compromesso con l'ambiente grafico. Se le due cose vanno nella stessa direzione allora Lubuntu è la distribuzione fatta proprio per voi!

venerdì 8 ottobre 2010

La classe InetAddress

La classe InetAddres (del package java.net) è in grado di rappresentare un indirizzo IP di rete. All'interno troviamo alcuni metodi statici (non hanno bisogno di un'istanza della classe) particolarmente utili:
  • static InetAddress[] getAllByName(String host): ritorna un array di indirizzi IP riconducibili al nome dell'host;
  • static InetAddress getByAddress(byte[] addr): ritorna un oggetto InetAddress a partire da un indirizzo IP (passato in forma binaria, per IPv4 occorrono 4 byte);
  • static InetAddress getByAddress(String host, byte[] addr): ritorna un oggetto InetAddress riconducibile ai paramatri host ed addr;
  • static InetAddress getByName(String host): ritorna un oggetto InetAddress corrispondente all'host passato;
In caso di errori, nome dell'host o indirizzo IP errato, questi metodi scatenano un'eccezione di tipo UnknownHostException, ragion per cui vanno sempre innescati all'interno di blocchi try/catch. Vi occorre sapere l'indirizzo IP di un host? Poche righe di codice e il problema è risolto:
package address;

import java.net.*;

public class AddressTest {
 public static void main(String[] args) {
  try {
   String hostname=args[0];
   InetAddress ip=InetAddress.getByName(hostname);
   System.out.println(" Hostname: "+hostname);
   System.out.println(" Indirizzo IP: "+ip.toString().substring(args[0].length()+1));
  }
  catch(ArrayIndexOutOfBoundsException e) {
   System.out.println("Attenzione: fornire il nome dell'host come parametro!");
  }
  catch(UnknownHostException e) {
   System.out.println("Attenzione: hostname sconosciuto!");
  }
 }
}

Qui trovate il file jar del programma.

giovedì 7 ottobre 2010

Applicazioni client/server con Java

La comunicazione e lo scambio dell'informazione sono da sempre alla base di Internet. Anche Java, nato inizialmente con lo stesso obiettivo, supporta la programmazione di rete. Il package java.net raccoglie le interfacce, le classi e le possibili eccezioni utili proprio alla programmazione per questo tipo di applicazioni, spesse volte dette anche applicazioni client/server.

Queste applicazioni osservano un noto modello di programmazione che è appunto il modello client/server. Durante lo scambio dell'informazione il suddetto modello assegna ai partecipanti dei ruoli ben precisi: il client è l'applicazione che, interfacciandosi attraverso la rete al server, richiede un preciso servizio; il server è invece quell'applicazione che soddisfa, attraverso la rete, la richiesta del client.

La comunicazione fra client e server si svolge inevitabilmente attraverso la rete, grazie ai protocolli di rete. A livello di trasporto essa può allora avvenire attraverso due dei principali protocolli di trasporto: TCP o UDP. Il protocollo di rete TCP realizza un canale logico per la connessione affidabile e orientato alla connessione, si impegna a fare del suo meglio per garantire l'arrivo dei pacchetti e l'ordine con cui essi vengono spediti. Il protocollo di rete UDP è assai più sbrigativo, non prevede una connessione e non garantisce ne l'arrivo ne l'ordine dei pacchetti. UDP viene usato, ad esempio, per lo streaming dei flusi audio e/o video. La scelta del protocollo per il trasporto può quindi variare in base al tipo di applicazione che abbiamo in mente.

Tale scelta va fatta ancora prima di mettersi a scrivere il codice dell'applicazione. Java implementa nel package jav.net diverse classi, alcune di queste sono orientate al protocollo TCP, altre invece seguono il protocollo UDP. La comunicazione fra client e server avviene attraverso le socket (presa o spina). Ogni applicazione si può dotare di una socket, la finestra sulla rete.

La classe Socket implementa uno dei due lati della connessione di rete (end-point) ed è orientata al protocollo TCP, tipicamente quella di un'applicazione client. La classe ServerSocket, invece, realizza la socket per l'applicazione server. Tale socket viene usata dai server per rimanere in ascolto e accettare le richieste di connessione dei client. La classe DatagramSocket realizza l'astrazione necessaria all'invio e alla ricezione dei dati attraverso il protocollo UDP.

In questo articolo mi occuperò esclusivamente delle classi Socket e ServerSocket. E' evidente che l'applicazione server deve trovarsi già in esecuzione prima di ricevere richieste dai client che altrimenti si perdono nella rete. Osserveremo allora prima la struttura di un'applicazione server. L'istanza di una socket per il server avviene attraverso il costruttore della classe ServerSocket:

public ServerSocket(int port) throws IOException

dove port rappresenta il numero di porta usato dal server, presso il proprio indirizzo di rete, per l'ascolto. Alcuni numeri di porta sono assegnati di default e spettano a vari servizi di rete (sono cioè usati da altri protocolli per applicazioni). Se l'istanza di una ServerSocket non riesce vi consiglio di cambiare il numero della porta usato nel costruttore, potrebbe infatti essere già impegnato! Il costruttore va poi eseguito all'interno di un blocco try/catch per intercettare proprio l'errore che vi descrivevo poco fa. Esistono altri tipi di cotruttori, date come sempre uno sguardo alla documentazione della classe:

server=new ServerSocket(10000);

Se l'istanza della socket riesce possiamo allora collocare la stessa in uno stato di attesa. Il metodo accept() blocca l'esecuzione del programma e lo pone in attesa di richieste di connessione. Il metodo si sblocca alla prima richiesta del client, ritornando l'oggetto socket usato dallo stesso! Da questo oggetto il server, se vuole, può estrarre l'indirizzo IP con il metodo getInetAddress():

client=server.accept();

Affinchè il server possa realmente mandare al client dei byte (testo o informazioni varie) deve necessariamente estrarre dalla socket del client gli stream per l'input:

input=new BufferedReader(new InputStreamReader(client.getInputStream()));
e per l'output:
output=new PrintWriter(client.getOutputStream(),true);
I metodi getInputStream() e getOutputStream() ritornano rispettivamente InputStream e OutputStream. La comunicazione adesso è davvero semplice, se il server intende leggere cosa ha scritto il client non deve fare altro che usare lo stream input. Nell'esempio ho appositamente convogliato lo stream di input in un oggetto BufferedReader che semplifica la lettura con il metodo readLine() (che ritorna una stringa). Per leggere, ad esempio, si potrebbe avere questa istruzione:
String clientMessage=input.readLine();
Se il server intende scrivere qualcosa al client userà allora lo stream di output:
output.println("Ciao!");
Prestate attenzione alla chiusura dell'applicazione e liberate sempre le risorse impegnate. Chiudete prima gli stream di input e di output, quindi la socket del client e infine quella del server:
input.close();
output.close();
client.close();
server.close();
L'applicazione client opera allo stesso modo di quella server, la prima operazione da fare è la connessione al server (che sarà in attesa, bloccato sul metodo accept()). Il client può allora usare la classe Socket in questo modo:
client=new Socket(ip,10000);
dove ip è la stringa con l'indirizzo ip del server e 10000 il numero di porta del servizio. Se la connessione riesce senza eccezzioni (anche questa operazione, così come le altre, va sempre innescata all'interno di un blocco try/catch) il client può allora ricavare dalla socket (ora connessa al client) gli stream per l'input e per l'output. Per l'input, come visto prima, ad esempio:
input=new BufferedReader(new InputStreamReader(client.getInputStream()));
per l'output, analogamente:
output=new PrintWriter(client.getOutputStream(),true);
Così come fa il server, anche il client può usare gli strem per scrivere al server e per leggerne i messaggi inviati dallo stesso, il protocollo TCP realizza infatti un canale bidirezionale. Le applicazioni client e server dovranno in ogni modo accordarsi su quando e come scriversi, dovranno cioè osservare un protocollo per lo scambio dei messaggi (un compito è lasciato alla fantasia del programmatore). Non dimenticate di chiudere nell'ordine esatto le risorse impegnate anche nell'applicazione client.
Qui potete scaricare l'archivio jar di un'applicazione server, a questo indirizzo invece trovate il client. Lanciate prima il server (con il comando "java -jar ServerSocket.jar", nella cartella che ospita il file scaricato) e successivamente il client (con "java -jar ClientSocket.jar", sempre nella cartella che ospita il file scaricato) se volete utilizzare l'applicazione nella vostra rete locale (con indirizzo ip di loopback 127.0.0.1). Altrimenti eseguite le due applicazioni su due computer con indirizzo ip differente. L'esecuzione del client inizia proprio con la richiesta dell'indirizzo ip del server (la porta usata è di default la 10000), se non conoscete il vostro indirizzo ip potete ricavarlo sfruttandore ad esempio i tanti servizi di rete, ad esempio qui. Qui potete vedere la parte server in esecuzione (su un computer con sistema operativo Linux, il mio Aspire One!):

Qui invece la parte client (in esecuzione su un PC con sistema operativo Windows XP):

L'applicazione permette lo scambio di messaggi fra client e server, dopo aver effettuato la connessione al server il client inizia a scrivere al server (che si mette quindi in attesa di un messaggio). Subito dopo è il client che si mette in attesa di un messaggio di risposta da parte del server. La comunicazione si svolge quindi su turni. Va inoltre osservata la capacità del server di rispondere a una sola richiesta di connessionne del client. Per implementare un server che accetta più connessioni quest'ultimo deve necessariamente usare una socket per l'ascolto e generare ad ogni connessione una socket per il client.