Leggere un InputStream utilizzando Java Server Socket

1. Panoramica

Per inviare e ricevere dati su una rete, utilizziamo spesso i socket. I socket non sono altro che una combinazione di un indirizzo IP e un numero di porta, che può identificare in modo univoco un programma in esecuzione su una determinata macchina.

In questo tutorial, mostreremo come leggere i dati che ci vengono inviati tramite un socket.

2. Lettura dei dati da un socket

Supponiamo di avere una conoscenza di base della programmazione socket.

Ora approfondiremo la lettura dei dati su una porta su cui il nostro server è in ascolto.

In primo luogo, dobbiamo dichiarare e inizializzare le variabili ServerSocket, Socket e DataInputStream :

ServerSocket server = new ServerSocket(port); Socket socket = server.accept(); DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));

Nota che abbiamo scelto di avvolgere InputStream del socket in un DataInputStream. Questo ci permette di leggere le righe di un testo e tipi di dati primitivi Java in modo portatile.

Questo è utile poiché ora, se conosciamo il tipo di dati che riceveremo, possiamo usare metodi specializzati come readChar (), readInt (), readDouble () e readLine ().

Tuttavia, può essere difficile se il tipo e la lunghezza dei dati non sono noti in anticipo.

In tal caso, otterremo un flusso di byte dal socket, invece, utilizzando la funzione read () di livello inferiore . Ma c'è un piccolo problema in questo approccio: come facciamo a sapere la lunghezza e il tipo di dati che otterremo?

Esploriamo questo scenario nella sezione successiva.

3. Lettura di dati binari da un socket

Quando si leggono i dati in byte, è necessario definire il proprio protocollo per la comunicazione tra server e client. Il protocollo più semplice che possiamo definire si chiama TLV (Type Length Value). Significa che ogni messaggio scritto nel socket ha la forma di Type Length Value.

Quindi definiamo ogni messaggio inviato come:

  • Un carattere a 1 byte che rappresenta il tipo di dati, come s per String
  • Un numero intero a 4 byte che indica la lunghezza dei dati
  • E poi i dati effettivi, la cui lunghezza è stata appena indicata

Una volta che il client e il server stabiliscono la connessione, ogni messaggio seguirà questo formato. Quindi, possiamo scrivere il nostro codice per analizzare ogni messaggio e leggere n byte di dati di un tipo specifico.

Vediamo come possiamo implementarlo usando un semplice esempio con un messaggio String .

Per prima cosa, dobbiamo chiamare la funzione readChar () , leggere il tipo di dati e quindi chiamare la funzione readInt () per leggerne la lunghezza:

char dataType = in.readChar(); int length = in.readInt();

Dopodiché, dobbiamo leggere i dati che stiamo ricevendo. Un punto importante da notare qui è che la funzione read () potrebbe non essere in grado di leggere tutti i dati in una chiamata. Quindi, dobbiamo chiamare read () in un ciclo while:

if(dataType == 's') { byte[] messageByte = new byte[length]; boolean end = false; StringBuilder dataString = new StringBuilder(length); int totalBytesRead = 0; while(!end) { int currentBytesRead = in.read(messageByte); totalBytesRead = currentBytesRead + totalBytesRead; if(totalBytesRead =length) { end = true; } } }

4. Codice cliente per inviare dati

E per quanto riguarda il codice lato client? In realtà, è abbastanza semplice:

char type = 's'; // s for string String data = "This is a string of length 29"; byte[] dataInBytes = data.getBytes(StandardCharsets.UTF_8); out.writeChar(type); out.writeInt(dataInBytes.length); out.write(dataInBytes);

È tutto ciò che fa il nostro cliente!

5. conclusione

In questo articolo, abbiamo discusso come leggere i dati da un socket. Abbiamo esaminato diverse funzioni che ci aiutano a leggere dati di un tipo particolare. Inoltre, abbiamo visto come leggere i dati binari.

L'implementazione completa di questo tutorial può essere trovata su GitHub.