Domanda Esercizio socket java

raf97

Utente Bronze
13 Ottobre 2017
32
9
1
32
Salve a tutti,
Io ho risolto un esercizio di un mio esame sulle socket in Java e vorrei sapere da voi gentilmente se e' giusto perche' e' da poco che mi sono addentrata nella programmazione Java.
Ho fatto diverse prove e sembrerebbe andare anche se Netbeans mi va un po' lentino nell'output, pero' vorrei sapere se sintatticamente andrebbe bene.

La traccia e' la seguente:

1. Legge da tastiera un hostname e un numero di posta;
2. Apre una connessione TCP verso il server avente quell'hostname e quel numero di porta;
3. Legge da tastiera 10 stringhe, una per riga, e le invia una per volta al server;
4. Riceve dal server una stringa e la stampa su video;
5. Chiude la connessione col server
Non e' richiesta l'implementazione del server.

Java:
import java.net.*;
import java.io.*;
public class Client3 {

    private static String hostname;

    public static void main(String[] args) throws IOException {
        Socket clientSocket=null;
        BufferedReader in=null, input=null;
        PrintWriter out=null;
        
        try {
            
            String str=input.readLine();
            System.out.println("Inserisci la stringa da convertire:"+str);
            
            int PORT=Integer.parseInt(str);
            System.out.println("La porta è:"+PORT);
            
            String hostname=input.readLine();
            System.out.println("Inserisci hostname:"+hostname);
            
            clientSocket= new Socket(hostname,PORT);
            System.out.println("Client socket:"+ clientSocket);
            
            InputStreamReader isr= new InputStreamReader (clientSocket.getInputStream());
            in= new BufferedReader(isr);
            
            OutputStreamWriter osw= new OutputStreamWriter (clientSocket.getOutputStream());
            BufferedWriter bw= new BufferedWriter(osw);
            out= new PrintWriter(bw, true);
            
            input= new BufferedReader(new InputStreamReader(System.in));
            
            
            while (true) {
                for (int i=0;i<10;i++){
                    String inviata= input.readLine();
                    System.out.println("Inserisci stringa da inviare al server:"+input.readLine());
                    out.println(inviata);
                    i++;
                }
                String ricevuta=in.readLine();
                System.out.println("La stringa ricevuta è:"+ricevuta);
            }
            
        }
        catch (UnknownHostException e) {
        System.err.println("Don’t know about host "+ hostname);
        System.exit(1);
        }
        catch (IOException e) {
        System.err.println("Couldn’t get I/O for the connection to: " + hostname);
        System.exit(1);
        }
  System.out.println("EchoClient: closing...");
  out.close();
  in.close();
  clientSocket.close();
        
        
    }
    
}
 
Premetto che Java non è un lang che amo e quindi non lo uso mai. Pertanto praticamente non lo conosco. E anche tutti i codici che scrivo non sono nemmeno testati.

1) Non vedo il senso del while(true): la traccia dice che devi mandare 10 stringhe, quindi riceverne una, e poi chiudere la connessione. Ma il codice che hai scritto non chiude mai la connessione (resta sempre dentro il ciclo while) e continua ripetutamente a mandare 10 stringhe e riceverne una.
2) Per leggere da tastiera puoi anche utilizzare la classe BufferedReader, ma tipicamente si utilizza la classe java.util.Scanner (va aggiunto l'import) in questo modo:
Java:
Scanner input = new Scanner(System.in);

System.out.print("Inserisci hostname: "); /* prima stampi il messaggio che chiede cosa inserire ... */
String hostname = input.nextLine(); /* ... dopo prendi l'input */
Inoltre, come ho scritto anche nei commenti, prima si stampa il messaggio che dice cosa si vuole prendere in input ("Inserisci hostname"), dopo si prende l'input. Mentre tu fai il contrario (prima prendi l'input e dopo stampi il messaggio di richiesta di input - non ha molto senso). Infatti, eseguendolo, dovrebbe risultarti l'output ritardato rispetto all'input.
Inoltre istanzi input dopo averla utilizzata (cosa che dovrebbe darti errore): mentre devi fare il contrario - prima le classi si istanziano (come ho fatto con la Scanner qui sopra) e poi si utilizzano.
La stessa cosa la fai dentro il ciclo for per la stringa da inviare - dovrebbe essere invece qualcosa del genere:
Java:
System.out.print("Inserisci la stringa da inviare al server: ");
String inviata = input.nextLine(); /* "inviata" non è proprio un bel nome. Semmai "daInviare" se proprio vuoi utilizzare nomi italiani per le variabili (che generalmente non è una buona idea) */
out.println(inviata);
3) All'inizio chiedi inutilmente in input una "stringa da convertire". La traccia non lo richiede. Di fatto poi questa stringa da convertire non la usi mai nel resto del codice.
4) Stampi a schermo clientSocket, che è una istanza della classe Socket che non penso possa essere convertita implicitamente in stringa e stampata.
5) il ciclo for aumenta due volte la variabile i (ci sono 2 i++). In questo modo, il ciclo viene eseguito solo 5 volte e non 10 come dovrebbe.

I passi in ordine che dovresti fare dovrebbero essere:
Codice:
1) Crei un oggetto della classe Scanner, lo chiami "input".
2) Stampi a schermo il messaggio "Inserisci hostname: ".
3) Leggi una riga (nextLine()) da tastiera (oggetto "input") e salvi il risultato in una variabile stringa che chiami "hostname".
4) Stampi a schermo il messaggio "Inserisci porta: ".
5) Leggi un intero (nextInt()) da tastiera (oggetto "input") e salvi il risultato in una variabile intera che chiami "port".
6) Crei un oggetto della classe Socket, passando "hostname" e "port" come parametri.
7) Crei gli oggetti "isr", "in", "osw", "bw", "out" esattamente come hai fatto nel codice che hai postato.
8) Inizio ciclo for: for(int i = 0; i < 10; i++).
9) Stampi a schermo il messaggio "Inserisci stringa da inviare: ".
10) Leggi una riga da tastiera (oggetto "input") e salvi il risultato in una variabile stringa che chiami "curstr".
11) Invii la stringa "curstr" sul socket (oggetto "out").
12) Fine ciclo for (viene ripetuto 10 volte).
13) Leggi una riga dal socket (oggetto "in") e la salvi in una variabile stringa che chiami "received".
14) Stampi a schermo la stringa salvata in "received".
15) Chiudi il socket terminando la connessione.
 
  • Mi piace
Reazioni: Fastidio
Il mio problema ora sta nel ciclo for, perche' non si interrompe.
Java:
while (true) {
                
                for (int i=0;i<10;i++){
                    System.out.println("Inserisci stringa da inviare al server:");
                    String daInviare= input.readLine();
                    out.println(daInviare);
                    
                }
                String ricevuta=in.readLine();
                System.out.println("La stringa ricevuta è:"+in.readLine());
            }
PS. Utilizzando per l'input da tastiera il BufferedReader funziona lo stesso, ma se mi puoi dare una piccola mano nel ciclo for te ne sarei veramente grata.
E poi un'ultima cosa, io ho implementato a parte il server e ho pure questo problema del ciclo for di ricezione di queste stringhe perche' risulta ricevuta solo la prima stringa inviata dal client e non tutte.
 
Il mio problema ora sta nel ciclo for, perche' non si interrompe.
Java:
while (true) {
               
                for (int i=0;i<10;i++){
                    System.out.println("Inserisci stringa da inviare al server:");
                    String daInviare= input.readLine();
                    out.println(daInviare);
                   
                }
                String ricevuta=in.readLine();
                System.out.println("La stringa ricevuta è:"+in.readLine());
            }
PS. Utilizzando per l'input da tastiera il BufferedReader funziona lo stesso, ma se mi puoi dare una piccola mano nel ciclo for te ne sarei veramente grata.
E poi un'ultima cosa, io ho implementato a parte il server e ho pure questo problema del ciclo for di ricezione di queste stringhe perche' risulta ricevuta solo la prima stringa inviata dal client e non tutte.
Mi sa che non si interrompe perché è dentro a un While infinito. E al server probabilmente non è che ne arrivi una sola, ma arrivano tutte e ogni volte la stringa sovrascrive quella ricevuta precedentemente... Hai provato a seguire con un debug?
 
Il mio problema ora sta nel ciclo for, perche' non si interrompe.
Hai messo il for dentro a un ciclo while(true) che non termina mai. Quindi quando il for termina, ricomincia da capo a causa del ciclo while esterno.
Devi cancellare il ciclo while esterno.
E poi un'ultima cosa, io ho implementato a parte il server e ho pure questo problema del ciclo for di ricezione di queste stringhe perche' risulta ricevuta solo la prima stringa inviata dal client e non tutte.
Serve che posti anche il codice del server. Senza il codice si può solo tirare a indovinare quale è il problema.
 
Ultima modifica:
Il fatto è che il professore il while (true) me lo fa mettere sempre.
Modifico le classi e le invio e invio anche il server.
Messaggio unito automaticamente:

Hai messo il for dentro a un ciclo while(true) che non termina mai. Quindi quando il for termina, ricomincia da capo a causa del ciclo while esterno.
Devi cancellare il ciclo while esterno.

Serve che posti anche il codice del server. Senza il codice si può solo tirare a indovinare quale è il problema.
Di seguito ti allego il for del Client
Java:
            //ho eliminato il while (true)   
                for (int i=0;i<10;i++){
                    System.out.println("Inserisci stringa da inviare al server:");
                    String daInviare= input.readLine();
                    out.println(daInviare);
                    
                }
                String ricevuta=in.readLine();
                System.out.println("La stringa ricevuta è:"+ricevuta);

Questo invece e' il server:
Java:
import java.io.*;
import java.net.*;
public class Server3 {

    private static int PORT=5135; //ho inserito una porta a caso
    public static void main(String[] args) throws IOException {
        ServerSocket ss= new ServerSocket(PORT); // creazione del socket
        Socket clientSocket=null;
        BufferedReader in= null, input=null;
        PrintWriter out= null;
        
        try{
            clientSocket= ss.accept();
            System.out.println("Connessione accettata:"+clientSocket);
            
            InputStreamReader isr= new InputStreamReader(clientSocket.getInputStream());
            in= new BufferedReader(isr);
            
            OutputStreamWriter osw= new OutputStreamWriter (clientSocket.getOutputStream());
            BufferedWriter bw= new BufferedWriter(osw);
            out= new PrintWriter(bw, true);
            
            input= new BufferedReader(new InputStreamReader(System.in));
            
            //while (true) {
                
                for (int i=0;i<10;i++) {
                    System.out.println("Stringhe ricevute dal client:"+in.readLine());
                    String ricevuta=in.readLine();
                    
                }
                
                System.out.println("Inserisci stringa da inviare al client:");
                String inviaAlClient=input.readLine();
                out.println(inviaAlClient);
            //}
            
        }
        catch (IOException e) {
            System.err.println("Accept failed");
            System.exit(1);
        }
  // chiusura di stream e socket
  System.out.println("EchoServer: closing...");
  out.close();
  in.close();
  clientSocket.close();
  ss.close();
        
    
}
}

Nell/output il server non so come mai ma invece ad esempio di ricevere i numeri da 1 a 10 dal client, solo quelli dispari riceve, saltando una stringa ricevuta tra l'una e l'altra.
 
Il fatto è che il professore il while (true) me lo fa mettere sempre.
Modifico le classi e le invio e invio anche il server.
Messaggio unito automaticamente:


Di seguito ti allego il for del Client
Java:
            //ho eliminato il while (true)  
                for (int i=0;i<10;i++){
                    System.out.println("Inserisci stringa da inviare al server:");
                    String daInviare= input.readLine();
                    out.println(daInviare);
                   
                }
                String ricevuta=in.readLine();
                System.out.println("La stringa ricevuta è:"+ricevuta);

Questo invece e' il server:
Java:
import java.io.*;
import java.net.*;
public class Server3 {

    private static int PORT=5135; //ho inserito una porta a caso
    public static void main(String[] args) throws IOException {
        ServerSocket ss= new ServerSocket(PORT); // creazione del socket
        Socket clientSocket=null;
        BufferedReader in= null, input=null;
        PrintWriter out= null;
       
        try{
            clientSocket= ss.accept();
            System.out.println("Connessione accettata:"+clientSocket);
           
            InputStreamReader isr= new InputStreamReader(clientSocket.getInputStream());
            in= new BufferedReader(isr);
           
            OutputStreamWriter osw= new OutputStreamWriter (clientSocket.getOutputStream());
            BufferedWriter bw= new BufferedWriter(osw);
            out= new PrintWriter(bw, true);
           
            input= new BufferedReader(new InputStreamReader(System.in));
           
            //while (true) {
               
                for (int i=0;i<10;i++) {
                    System.out.println("Stringhe ricevute dal client:"+in.readLine());
                    String ricevuta=in.readLine();
                   
                }
               
                System.out.println("Inserisci stringa da inviare al client:");
                String inviaAlClient=input.readLine();
                out.println(inviaAlClient);
            //}
           
        }
        catch (IOException e) {
            System.err.println("Accept failed");
            System.exit(1);
        }
  // chiusura di stream e socket
  System.out.println("EchoServer: closing...");
  out.close();
  in.close();
  clientSocket.close();
  ss.close();
       
   
}
}

Nell/output il server non so come mai ma invece ad esempio di ricevere i numeri da 1 a 10 dal client, solo quelli dispari riceve, saltando una stringa ricevuta tra l'una e l'altra.



solitamente il while(true) si mette per far rimanere il socket in ascolto ma in questo caso puoi anche farne a meno
 
Ultima modifica:
Di seguito ti allego il for del Client
Il for ora va bene.
Giusto per essere sicuri che si sta lavorando con lo stesso codice, incollo qui il codice del client finale corretto di tutti i problemi elencati sopra (utilizzo la Scanner per l'input da tastiera: è il modo più standard e semplice di gestire l'input):

CLIENT:
Java:
import java.io.*;
import java.net.*;
import java.util.Scanner;

public class Client {
	public static void main(String[] args) {
		Socket clientSocket = null;
		Scanner input = new Scanner(System.in);
		BufferedReader in = null;
		PrintWriter out = null;
		String hostname;
		int port;

		try {
			System.out.print("Inserisci hostname: ");
			hostname = input.nextLine();
			System.out.print("Inserisci porta: ");
			port = input.nextInt();

			/* nextInt() lascia il carattere newline dentro al
			 * buffer di input, quindi con nextLine() avanziamo
			 * fino alla prossima riga */
			input.nextLine();

			clientSocket = new Socket(hostname, port);

			InputStreamReader isr = new
				InputStreamReader(clientSocket.getInputStream());
			in = new BufferedReader(isr);

			OutputStreamWriter osw = new
				OutputStreamWriter(clientSocket.getOutputStream());
			BufferedWriter bw = new BufferedWriter(osw);
			out = new PrintWriter(bw, true);

			for (int i = 0; i < 10; i++) {
				System.out.print("Inserisci la " + (i + 1) + "a stringa da inviare al server: ");
				String daInviare = input.nextLine();
				out.println(daInviare);
			}

			String ricevuta = in.readLine();
			System.out.println("La stringa ricevuta è: " + ricevuta);
		} catch (UnknownHostException e) {
			System.err.println(e.getMessage());
		} catch (IOException e) {
			System.err.println(e.getMessage());
		} finally {
			/* Il blocco finally viene eseguito sempre dopo il try,
			 * anche in caso si sia verificata una eccezione catch.
			 * In questo modo clientSocket, out e in vengono chiusi
			 * anche se l'esecuzione del try si è interrotta per un
			 * errore */
			try {
				if (out != null)
					out.close();
				if (in != null)
					in.close();
				if (clientSocket != null)
					clientSocket.close();
			} catch (IOException e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
		}
	}
}

Parlando del server:
Il tuo problema è dato dal fatto che dentro al ciclo for leggi l'input due volte:
Java:
System.out.println("Stringhe ricevute dal client:"+in.readLine());
String ricevuta=in.readLine();
Vedi che richiami readLine() due volte. Quello che vuoi è PRIMA prendere l'input dentro la stringa ricevuta e DOPO stampare a schermo il contenuto della stringa:
Java:
String ricevuta = in.readLine();
System.out.println("Stringhe ricevute dal client: " + ricevuta);
Un dettaglio: tipicamente un server è fatto per essere always on: dopo aver servito un client, deve nuovamente mettersi in attesa di connessione da nuovi client. Quindi, tipicamente, tutto il codice di un server (dall'accettazione della connessione fino alla sua chiusura) viene messo dentro un while(true).

Qui il codice finale corretto del server:
Java:
import java.io.*;
import java.net.*;
import java.util.Scanner;

public class Server {
	private static int PORT = 5135;

	public static void main(String[] args) {
		ServerSocket ss = null;
		Scanner input = new Scanner(System.in);
		Socket clientSocket = null;
		BufferedReader in = null;
		PrintWriter out = null;

		try {
			ss = new ServerSocket(PORT);
			while (true) {
				clientSocket = ss.accept();
				System.out.println("Nuova connessione accettata");

				InputStreamReader isr = new
					InputStreamReader(clientSocket.getInputStream());
				in = new BufferedReader(isr);

				OutputStreamWriter osw = new
					OutputStreamWriter(clientSocket.getOutputStream());
				BufferedWriter bw = new BufferedWriter(osw);
				out = new PrintWriter(bw, true);

				for (int i = 0; i < 10; i++) {
					String ricevuta = in.readLine();
					System.out.println("Stringa ricevuta: " + ricevuta);
				}
				System.out.print("Inserisci stringa da inviare al client: ");
				String inviaAlClient = input.nextLine();
				out.println(inviaAlClient);

				out.close();
				in.close();
				clientSocket.close();
			}
		} catch (IOException e) {
			System.err.println(e.getMessage());
		} finally {
			try {
				if (out != null)
					out.close();
				if (in != null)
					in.close();
				if (clientSocket != null)
					clientSocket.close();
				if (ss != null)
					ss.close();
			} catch (IOException e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
		}
	}
}


Il fatto è che il professore il while (true) me lo fa mettere sempre.
Va bene nel server (come ho fatto io), in quanto deve essere always on e deve servire più client. Quindi il while(true) serve a non far terminare il server e continuare ad accettare nuove richieste.
Può andar bene nel client, ma dipende da cosa devi fare. Nel caso dell'esercizio che hai postato in questa discussione il while(true) non ha senso. Anzi: il testo dell'esercizio chiede proprio di fare un client che alla fine chiude la connessione con il server quindi usare un ciclo while infinito è proprio un errore in quanto impedisce al programma di chiudere la connessione e terminarsi. Aveva invece senso metterlo se il testo dell'esercizio fosse stato:
1. Legge da tastiera un hostname e un numero di porta;
2. Apre una connessione TCP verso il server avente quell'hostname e quel numero di porta;
3. Legge da tastiera 10 stringhe, una per riga, e le invia una per volta al server;
4. Riceve dal server una stringa e la stampa su video;
5. Torna al punto 3.

Il passo 5 è ciò che richiede il ciclo while infinito: il client non termina mai e continua sempre a mandare nuove stringhe al server.
 
  • Mi piace
Reazioni: 0xbro
Il for ora va bene.
Giusto per essere sicuri che si sta lavorando con lo stesso codice, incollo qui il codice del client finale corretto di tutti i problemi elencati sopra (utilizzo la Scanner per l'input da tastiera: è il modo più standard e semplice di gestire l'input):

CLIENT:
Java:
import java.io.*;
import java.net.*;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) {
        Socket clientSocket = null;
        Scanner input = new Scanner(System.in);
        BufferedReader in = null;
        PrintWriter out = null;
        String hostname;
        int port;

        try {
            System.out.print("Inserisci hostname: ");
            hostname = input.nextLine();
            System.out.print("Inserisci porta: ");
            port = input.nextInt();

            /* nextInt() lascia il carattere newline dentro al
             * buffer di input, quindi con nextLine() avanziamo
             * fino alla prossima riga */
            input.nextLine();

            clientSocket = new Socket(hostname, port);

            InputStreamReader isr = new
                InputStreamReader(clientSocket.getInputStream());
            in = new BufferedReader(isr);

            OutputStreamWriter osw = new
                OutputStreamWriter(clientSocket.getOutputStream());
            BufferedWriter bw = new BufferedWriter(osw);
            out = new PrintWriter(bw, true);

            for (int i = 0; i < 10; i++) {
                System.out.print("Inserisci la " + (i + 1) + "a stringa da inviare al server: ");
                String daInviare = input.nextLine();
                out.println(daInviare);
            }

            String ricevuta = in.readLine();
            System.out.println("La stringa ricevuta è: " + ricevuta);
        } catch (UnknownHostException e) {
            System.err.println(e.getMessage());
        } catch (IOException e) {
            System.err.println(e.getMessage());
        } finally {
            /* Il blocco finally viene eseguito sempre dopo il try,
             * anche in caso si sia verificata una eccezione catch.
             * In questo modo clientSocket, out e in vengono chiusi
             * anche se l'esecuzione del try si è interrotta per un
             * errore */
            try {
                if (out != null)
                    out.close();
                if (in != null)
                    in.close();
                if (clientSocket != null)
                    clientSocket.close();
            } catch (IOException e) {
                System.err.println(e.getMessage());
                System.exit(1);
            }
        }
    }
}

Parlando del server:
Il tuo problema è dato dal fatto che dentro al ciclo for leggi l'input due volte:
Java:
System.out.println("Stringhe ricevute dal client:"+in.readLine());
String ricevuta=in.readLine();
Vedi che richiami readLine() due volte. Quello che vuoi è PRIMA prendere l'input dentro la stringa ricevuta e DOPO stampare a schermo il contenuto della stringa:
Java:
String ricevuta = in.readLine();
System.out.println("Stringhe ricevute dal client: " + ricevuta);
Un dettaglio: tipicamente un server è fatto per essere always on: dopo aver servito un client, deve nuovamente mettersi in attesa di connessione da nuovi client. Quindi, tipicamente, tutto il codice di un server (dall'accettazione della connessione fino alla sua chiusura) viene messo dentro un while(true).

Qui il codice finale corretto del server:
Java:
import java.io.*;
import java.net.*;
import java.util.Scanner;

public class Server {
    private static int PORT = 5135;

    public static void main(String[] args) {
        ServerSocket ss = null;
        Scanner input = new Scanner(System.in);
        Socket clientSocket = null;
        BufferedReader in = null;
        PrintWriter out = null;

        try {
            ss = new ServerSocket(PORT);
            while (true) {
                clientSocket = ss.accept();
                System.out.println("Nuova connessione accettata");

                InputStreamReader isr = new
                    InputStreamReader(clientSocket.getInputStream());
                in = new BufferedReader(isr);

                OutputStreamWriter osw = new
                    OutputStreamWriter(clientSocket.getOutputStream());
                BufferedWriter bw = new BufferedWriter(osw);
                out = new PrintWriter(bw, true);

                for (int i = 0; i < 10; i++) {
                    String ricevuta = in.readLine();
                    System.out.println("Stringa ricevuta: " + ricevuta);
                }
                System.out.print("Inserisci stringa da inviare al client: ");
                String inviaAlClient = input.nextLine();
                out.println(inviaAlClient);

                out.close();
                in.close();
                clientSocket.close();
            }
        } catch (IOException e) {
            System.err.println(e.getMessage());
        } finally {
            try {
                if (out != null)
                    out.close();
                if (in != null)
                    in.close();
                if (clientSocket != null)
                    clientSocket.close();
                if (ss != null)
                    ss.close();
            } catch (IOException e) {
                System.err.println(e.getMessage());
                System.exit(1);
            }
        }
    }
}



Va bene nel server (come ho fatto io), in quanto deve essere always on e deve servire più client. Quindi il while(true) serve a non far terminare il server e continuare ad accettare nuove richieste.
Può andar bene nel client, ma dipende da cosa devi fare. Nel caso dell'esercizio che hai postato in questa discussione il while(true) non ha senso. Anzi: il testo dell'esercizio chiede proprio di fare un client che alla fine chiude la connessione con il server quindi usare un ciclo while infinito è proprio un errore in quanto impedisce al programma di chiudere la connessione e terminarsi. Aveva invece senso metterlo se il testo dell'esercizio fosse stato:
1. Legge da tastiera un hostname e un numero di porta;
2. Apre una connessione TCP verso il server avente quell'hostname e quel numero di porta;
3. Legge da tastiera 10 stringhe, una per riga, e le invia una per volta al server;
4. Riceve dal server una stringa e la stampa su video;
5. Torna al punto 3.

Il passo 5 è ciò che richiede il ciclo while infinito: il client non termina mai e continua sempre a mandare nuove stringhe al server.

Sei un grande, sei stato gentilissimo. Grazie. Ora mi sono chiare un pò di cose.