I passi
da fare
Prima
di mostrarvi il codice ecco una lista delle operazioni da fare da ambo
i lati (client e server) per instaurare una connessione tra due macchine.
Lato client
Siccome
e' da qui che parto per arrivare al server, e' qui che devo sapere sia
l'IP della macchina destinataria che la porta a cui mi voglio connettere...
sperando di trovare qualcuno dall'altra parte ;-)
-
istanzio
un oggetto Socket (passando IP e porta)
-
se non
ho avuto eccezioni ho in mano una connessione attivata
-
mi faccio
dare (dalla Socket) i due canali (streams) per mandare e ricevere dati
-
mando
e ricevo usando .write() e .read() sugli streams
Lato server
Qui
invece ho bisogno solo di decidere una porta su cui mettermi in ascolto...
-
istanzio
un oggetto ServerSocket (passando la porta di ascolto)
se
non ho avuto eccezioni posso attendere connessioni (l'istanziazione
della
ServerSocket corrisponde all'operazione di BIND nella terminologia
TCP/IP)
-
mi metto
in attesa di connessioni (.accept()), la accept e' bloccante, esce solo
quando viene ricevuta una connessione dall'esterno (il nostro client o
un telnet ad esempio)
-
la accept
ritorna un'istanza di Socket...
-
mi faccio
dare (dalla Socket) i due canali (streams) per mandare e ricevere dati
mando e ricevo usando .write() e .read() sugli streams
Notate
che le ultime due voci sono uguali nel server e nel client?
E'
cosi' poiche' in realta' client e server sono identici dopo aver instaurato
la
connessione,
entrambi hanno in mano una istanza di Socket (una per lato della
connessione)
e lavorano su quella.
E'
esattamente come quando si fa una telefonata: uno chiama, l'altro risponde,
ma
quando state parlando non si distingue piu' chi aveva chiamato (cioe' se
qualcuno
vi guarda non riesce a capire se avevate chiamato voi o avevate
ricevuto).
A volte (specie se state molto tempo al telefono ;-) neanche voi vi
ricordate
chi aveva chiamato in origine...
Codice client
import
java.net.*;
import
java.io.*;
public
class Client{
public
static void main(String arg[]) {
try {
int port=2000; // porta su cui iniziare la connessione
Socket s=new Socket("127.0.0.1",port);
System.out.println("connected: "+s);
InputStream i=s.getInputStream();
OutputStream o=s.getOutputStream();
o.write('c'); // mando
o.write('i'); // mando
o.write('a'); // mando
o.write('o'); // mando
System.out.print(i.read()); // ricevo e stampo
System.out.print(i.read()); // ricevo e stampo
System.out.print(i.read()); // ricevo e stampo
System.out.print(i.read()); // ricevo e stampo
}
catch(Exception e) {
e.printStackTrace();
}
}
}
Socket server
import
java.net.*;
import
java.io.*;
public
class Server{
public static void main(String argv[]) {
try {
int port=2000; // porta di ascolto
ServerSocket server=new ServerSocket(port);
System.out.println("accepting... on port:"+port);
// la accept e' bloccante fino all'arrivo
// di una connessione
Socket s=server.accept();
System.out.println("... accepted:"+s);
InputStream i=s.getInputStream();
OutputStream o=s.getOutputStream();
while(true) // ciclo di echo dei caratteri {
int c = i.read();
System.out.print((char)c);
o.write(c);
}
}
catch(Exception e) {
e.printStackTrace();
}
}
}
Naturalmente
se fate girare questi due programmini (potete farlo sulla stessa
macchina,
da due finestre DOS separate) otterrete un errore sul server, dato che
lui
continua ad aspettarsi dati da rimandare indietro mentre il client ad un
certo
punto
termina.
Se
invece usate "telnet" avrete l'errore solo nel momento in cui chiuderete
la
connessione
esplicitamente.
Una
cosa molto interessante da testare e' quella di lanciare il server, connettersi
con
un telnet e poi provare a lanciare il client... che succede?
Succede
che il vostro client non riesce a parlare col server, questo perche' e'
gia'
occupato
a "servire" un altro "cliente" (il telnet).
Nelle
prossime puntate vedremo come creare piu' thread per avere
contemporaneamente
in funzione un ciclo di attesa di connessioni e anche il
codice
di risposta alle connessioni gia' effettuate.
Note
Potreste
non ottenere niente (sia il client che il server si bloccano e non
spediscono
ne' ricevono dati), in questi casi provate a scambiare l'ordine di
chiamata
dei metodi getInputStream() e getOutputStream() in uno dei due
programmi.
E' un baco, e non so se nelle versioni recenti del JDK e' stato
risolto...
Volete
divertirvi con gli amici? (si fa per dire ;-) provate a sostituire nel
server la linea:
o.write(c);
con:
o.write(c+1);
Poi provate
a contattare il server con un telnet invece che col client java... cosa
succede?
A voi gli esperimenti...
Nelle
prossime puntate impareremo a spedire dati complessi (perfino oggetti
interi),
vedremo UDP (quella che abbiamo usato ora e' una connessione TCP) e
vedremo
come si possono gestire intelligentemente alcuni tipi di connessioni (es.
HTTP). |