MokaByte Numero  37  - Gennaio 2000
Networking in Java
II puntata: i socket
 La pratica

 


 
di
Andrea Trentini
Come iniziare a spedire dati da un host all'altro 


 

Dopo la teoria (Lorenzo Bettini) facciamo un piccolo esperimento: spediamo dei
                  byte da una macchina all'altra e vediamo cosa succede... naturalmente avendo prima creato un server che rimandi indietro qualcosa ;-) 

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).

MokaByte rivista web su Java

MokaByte ricerca nuovi collaboratori. 
Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it