Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 14
  1. #1

    [JAVA] Funzionamento non coerente di ObjectOutputStream

    Salve a tutti!!!!!

    Mi scuso innanzitutto qualora dovessi aver sbagliato a inserire questa discussione qui; è dovuto alla mia poca esperienza col forum a cui spero di abituarmi presto.
    Cercherò di esporre dettagliatamente il problema che mi si è posto davanti e che mi sta facendo sbattere la testa da un pò di tempo ormai. Il contesto innanzitutto, anche se non dovrebbe servire a molto. L'applicazione che sto implementando, a scopo didattico, è una Chat Avanzata con funzionalità di messagistica istantanea,creazione gruppi,scambio e/o condivisione file con il supporto del DBMS MySQL. Il funzionamento generale dovrebbe essere(almeno per la versione base) questo: un client si connette al server, comunicando attraverso un protocollo, e fa richiesta,via via, di tutto ciò che gli serve (ex: lista amici, lista gruppi, registrazione di un utente, ricerca di un utente ecc ecc...); il server reinvia le informazioni richieste dal client che ne ha fatto domanda. Un classico modello client-server che attualmente funziona e con cui non ho avuto problemi. Spero di non essere stato lungo nell' introduzione, ma cerco di dare più informazioni possibili. Andiamo al problema vero e proprio. Quando un utente X cerca di contattare un utente Y(invio di una semplice stringa), con cui è "amico" (ed online), il server, che agisce da relay tra i due client, dovrà creare un'autostrada virtuale tra essi; una volta ricevuto il messaggio da X deve inoltrarlo a Y e per far ciò ha bisogno della socket con cui è "connesso" direttamente ad Y. I modi di immagazzinare le socket connesse al server possono essere diverse a seconda delle varie implementazioni. Poichè ne ho provate diverse, e tutte, ahimè, non funzionano ne espongo una per semplicità. Il server prende la socket da un HashTable, in cui ci sono tutti gli utenti attualmente loggati all'applicazione, (con key= Y e value = socket) e inizializza un oggetto ObjectOutputStream( già ampiamente usato per i metodi in cui il server reinvia informazioni richieste da un utente) e lo usa per "inoltrare" il messaggio a Y. Premesso che "catturo" tutte le possibili eccezioni, runtime non avviene nulla, ovvero X scrive il suo messaggio per Y, il server(che riceve il messaggio) fa le operazioni sopra descritte e scrive sull'output stream di Y e l'applicazione continua normalmente. Nessuna eccezione, nessun errore, nessuna notifica nella parte di codice predisposta al "fetching" delle richieste da parte del client(in questo caso di Y); è come se l'oggetto spedito fosse completamente perso e non se ne ha più traccia.
    Oltre questa implementazione ne ho provate altre; ma tutte hanno portato allo stesso esito, quello sopra descritto. Per esempio sono riuscito ad evitare di conservare le socket in una struttura dati e tramite una classe da me definita, che ho chiamato "Board", scrivo dentro i messaggi da inviare ai singoli utenti e tramite un thread per singolo utente spedisco tramite il "proprio" outputstream le stringhe da inviare. Il meccanismo dovrebbe essere in poche parole questo: un thread per l'utente A, che gira sul server, e controlla la Board di A (in cui ci sono tutti i messaggi rivolti all'utente A), e se ne trova, li spedisce direttamente. In questo modo non avrebbe bisogno di trovare la socket appartenente ad un utente particolare, dato che è quel thread stesso che si occupa dell' input/output per quell'utente (un pò come avveniva nel meccanismo descritto all'inizio per le richieste che un client faceva al server).
    Ovviamente ci saranno diverse e varie e probabilmente migliori implementazioni anche a livello computazionale di questo meccanismo molto semplice. Aldilà dell'efficienza computazionale tutte portano allo stesso esito.

    Spero (tantissimo) possiate aiutarmi e riusciate a darmi delucidazioni su questo comportamento anomalo.

    Vi ringrazio tutti anticipatamente.

    Buona giornata.

  2. #2

    Re: [JAVA] Funzionamento non coerente di ObjectOutputStream

    Originariamente inviato da ilrosso211
    Premesso che "catturo" tutte le possibili eccezioni, runtime non avviene nulla, ovvero X scrive il suo messaggio per Y, il server(che riceve il messaggio) fa le operazioni sopra descritte e scrive sull'output stream di Y e l'applicazione continua normalmente. Nessuna eccezione, nessun errore, nessuna notifica nella parte di codice predisposta al "fetching" delle richieste da parte del client(in questo caso di Y); è come se l'oggetto spedito fosse completamente perso e non se ne ha più traccia.
    Oltre questa implementazione ne ho provate altre; ma tutte hanno portato allo stesso esito, quello sopra descritto.
    Il problema potrebbe essere a livello di rete e non nell'applicazione. Quindi, potrebbe dipendere da dove hai eseguito il test.

    In ogni caso, potresti postare un po' di codice. In questo modo è difficile capire dov'è realmente il problema.

  3. #3

    Re: Re: [JAVA] Funzionamento non coerente di ObjectOutputStream

    Originariamente inviato da VincenzoTheBest
    Il problema potrebbe essere a livello di rete e non nell'applicazione. Quindi, potrebbe dipendere da dove hai eseguito il test.
    Intanto grazie per la risposta. Comunque potrebbe darsi. Ma lo escluderei solamente perchè è stato testato in locale(clients e server in localhost), e su calcolatori differenti nella stessa rete locale(clients su due e server su un altro), e in entrambi i casi tutte le altre richieste, che il client faceva al server(un altro esempio,oltre quelli già scritti sopra è la lista degli interessi di un utente che viene correttamente inviata dal server (a seguito della richiesta) e ricevuta dal client), funzionano alla grande.
    Ora posto il codice, che in questo momento, si occupa di inviare un messaggio destinato al client Y inviato da un client X;
    il codice,ovviamente lato server, sarà un thread che si occupa di controllare una "lavagna virtuale" in cui sono scritti tutti i messaggi per Y e una volta trovatone uno lo invia tramite l'oggetto ObjectOutputStream;

    Non è ben indentato a causa del fatto che è stato copiato e incollato.

    codice:
    public class Client extends Thread{      
    
        public Client(Socket client) throws IOException{         
             this.client = client;         
             this.in = new ObjectInputStream(client.getInputStream());    
             this.out = new ObjectOutputStream(client.getOutputStream());     
        }     
     
        public Socket getClientSocket() {         
             return client;    
        }      
    
        public void setClientUsername(String clientUsername) {   
             this.clientUsername = clientUsername;   
        }     
     
         public void run(){                
             try{            
                 receiveMess();                
             }         
             catch(IOException ex){    
                  System.out.println(ex.getMessage());       
             }             
         }    
    
         public void receiveMess() throws IOException{       
             while(true){                         
                   ArrayList<String> myBoard = ServerAccept.getBoard(this.clientUsername);           
                   if(!myBoard.isEmpty()){          
                            String x = (String) myBoard.remove(myBoard.size() - 1);    
                            this.out.writeObject(new Packet(666, "PROVA"));  /*uscito il pacchetto da qui non se ne ha più notizia,     aggiungo che Packet(classe creata da me) implementa Serializable e funziona in tutti gli altri casi in cui l'ho usato */    
                   }    
             }    
          }    
            
       public ObjectOutputStream getOut(){        
              return this.out;           
       }    
         
       public String getUsername(){     
               return this.clientUsername;    
       }     
           
       public ObjectInputStream getIn(){               
            return this.in;   
       }         
    
     public void sendMess(Object payload) throws SQLException, IOException{  
            Vector received;       
            Vector toSend;     
            PreparedStatement query;         
            Connection con = null;        
            ResultSet rs;        
            Packet response;      
            int id;         
            received = (Vector) payload;               
            try{             
                con = Database.getCon();            
               query = con.prepareStatement("SELECT `idUser` FROM `AdvancedChat`.`User` WHERE `Username` = ?");            
               query.setObject(1, received.get(2));       
               rs = query.executeQuery();        
               rs.next();         
               id = rs.getInt("idUser");            
               toSend = new Vector();        
               toSend.add(0,received.get(0));//sender       
               toSend.add(1,received.get(1));//messaggio    
               response = new Packet(6,toSend);                
               ArrayList<String> receiverBoard = ServerAccept.getBoard((String) received.get(2));                     
    
              System.out.println(received.get(1)+" "+received.get(2));
      /*il server virtualizzato per l'utente X aggiungie alla "lavagna" per l'utente Y il messaggio da X verso Y*/    
              receiverBoard.add((String) received.get(1));           
              }          
             catch(SQLException ex){          
                  response = new Packet(666, "Ci sono dei problemi tecnici nella Chat");      
                  this.out.writeObject(response);         
             }       
             }    
             }        
       private ObjectInputStream in;     
       private ObjectOutputStream out;   
       private String clientUsername;    
       private Socket client;
     }

  4. #4

    Re: Re: Re: [JAVA] Funzionamento non coerente di ObjectOutputStream

    Originariamente inviato da ilrosso211
    codice:
    public class Client extends Thread{      
    
        public Client(Socket client) throws IOException{         
             this.client = client;         
             this.in = new ObjectInputStream(client.getInputStream());    
             this.out = new ObjectOutputStream(client.getOutputStream());     
        }
    Istanzia prima ObjectOutputStream, altrimenti si blocca.

  5. #5

    Re: Re: Re: Re: [JAVA] Funzionamento non coerente di ObjectOutputStream

    Originariamente inviato da VincenzoTheBest
    Istanzia prima ObjectOutputStream, altrimenti si blocca.
    Scusami non ho capito cosa intendi?che devo instanziare non nel costruttore o che devo instanziare a null e poi collegarlo all'outputstream della socket??o altro?

    scusami ancora e grazie per la pazienza.

  6. #6

    Re: Re: Re: Re: Re: [JAVA] Funzionamento non coerente di ObjectOutputStream

    Originariamente inviato da ilrosso211
    Scusami non ho capito cosa intendi?
    Intendo che devi invertire l'ordine di istanziazione degli stream:

    codice:
             this.out = new ObjectOutputStream(client.getOutputStream());  
             this.in = new ObjectInputStream(client.getInputStream());

  7. #7

    Re: Re: Re: Re: Re: Re: [JAVA] Funzionamento non coerente di ObjectOutputStream

    Originariamente inviato da VincenzoTheBest
    Intendo che devi invertire l'ordine di istanziazione degli stream:

    codice:
             this.out = new ObjectOutputStream(client.getOutputStream());  
             this.in = new ObjectInputStream(client.getInputStream());
    Ho testato più volte. Purtroppo il risultato è il medesimo. E' veramente curiosa come cosa..Può essere un problema relativo all'attività del Garbage Collector??Qualcuno ha qualche idea su quale sia il problema?

    Saluti.

    Ilrosso211

  8. #8
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,320
    Io non ho ben capito se la progettazione che hai fatto lato server sia corretta o meno (hai postato il client, che mi sembra corretto, ma non si sa nulla del server). Ti spiego, a grandi linee, come dovrebbe funzionare lato server.

    Ciascun client collegato al server è servito da un thread. Quindi ti serve una classe che modelli il thread. E' il thread a possedere la socket generata dalla connessione e i relativi ObjectInput/OutputStreams.
    La classe del thread deve esporre un metodo per permettere al server di poter inviare messaggi al client che essa gestisce e deve avere un riferimento al server per potergli comuinicare informazioni di servizio.
    Il server manterrà in una struttura dati apposita tutte le istanze dei thread di gestione dei client (la HashMap va benissimo!).
    Quando un client richiede l'invio di un messaggio "privato" (il tipo di messaggio/richiesta dovrebbe essere parte del protocollo di comunicazione) il server deve solo andare a prelevare il thread che gestisce il destinatario e spedirgli il messaggio usando il metodo esposto a tale scopo (quello di cui parlavo prima).
    Fine.

    Vediamo un po' di pseudo-codice:

    Il thread che gestisce il singolo client (lato server)
    codice:
    public class ClientThread extends Thread {
       private Server theServer;
       private Socket socket;
       private ObjectInputStream ois;
       private ObjectOutputStream oos;
       private String nome;
    
       public ClientThread(Server theServer, Socket socket) {
          this.theServer = theServer;
          this.socket = socket;
          nome = "";   // Il nome mi arriverà tramite protocollo
       }
    
       @Override
       public void run() {
          try {
             oos = new ObjectOutputStream( socket.getOutputStream() );
             ois = new ObjectInputStream( socket.getInputStream() );
    
             while( !isInterrupted() ) {
                // Gestisco i messaggi in arrivo dal client
                Message m = (Message) ois.readObject();
    
                // Li elaboro
                dispatchMessage( m );
             }
          } catch (...) { ... }
       }
    
       // Questo metodo verrà invocato all'interno di "dispatchMessage",
       // quando il client mi comunica il suo nome utente
       private void setNome(String nome) {
          this.nome = nome;
    
          // Comunico il mio nome al server, così può rintracciarmi
          theServer.setClientName(this, nome);
       }
       
       public void sendMessage(Message m) throws Exception {
          // Invio un messaggio al client
          oos.writeObject();
          oos.flush();
       }
       
    }
    Vediamo il server (solitamente, anch'esso è un Thread)

    codice:
    public class Server extends Thread {
       private HashMap<String,ClientThread> myClients = new HashMap<String,ClientThread>();
       private ServerSocket server;
    
       ...
    
       @Override
       public void run() {
          try {
             server = new ServerSocket( porta );
             while( !isInterrupted() ) {
                Socket s = server.accept();
    
                // E' arrivata una connessione... ne delego la gestione ad un nuovo thread
                (new ClientThread(this, s)).start();
             }
          } catch ( ... ) { ... }
       }
    
       public void setClientName(ClientThread ct, String nome) {
          // Il client mi ha comunicato il suo nome... posso mapparlo!
          myClients.put(nome, ct);
       }
    
       public void sendPrivateMessage(Message m, String destinatario) {
          // Quando arriva un messaggio privato, il thread che gestisce il client invocherà questo metodo
    
          // Recupero il thread che gestisce il destinatario
          ClientThread clDest = myClients.get( destinatario );
    
          // Gli invio il messaggio privato
          clDest.sendMessage( m );
       }
    }
    Questa è l'ossatura di base della gestione. L'ordine con cui ho aperto gli streams è coerente con l'ordine in cui tu apri gli stream sul client (mi sono basato sul codice che hai postato).


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  9. #9
    Grazie per le risposte e scusate la poca tempestività delle mie di risposte.
    Avevo già compreso il sistema client-server e la classe che ho postato era proprio lato Server anche se chiamata molto ambiguamente Client. Nel post iniziale avevo descritto il mio sistema client server che funzionava perfettamente. Nel caso della messagistica istantanea il sistema client-server si deve modificare un po' ed era proprio questo il mio limite. Il server è impossibilitato a stimolare in modo asincrono un client,ovvero quello che tentavo di fare (prendendo una socket da una struttura dati e senza preavviso utilizzare un OutputStream per inviare messaggi). Può solo rispondere se gli è stata fatta una richiesta diretta da un client(comunicazione client 'x' - server - client 'x'), che, infatti, era l'unica struttura di comunicazione che funzionava all'interno della mia applicazione. Ecco spiegato il motivo per cui non avevo nessun errore nè output nel debugging dell'applicazione,proprio perchè concettualmente era una azione erronea da fare ma per l'applicazione del tutto plausibile.

    Grazie a tutti per la disponibilità.

    PS: attendo disposizioni su come trattare la discussione "risolta".

  10. #10
    Stai implementando questa applicazione a scopo "didattico", dovresti cercare di metterci un po' del tuo per risolvere la cosa.
    Ad ogni modo, hai ben chiaro che il giro funziona quando il client chiede e il server risponde.
    Non potresti fare in modo che il client faccia polling verso il server per controllare se ci sono nuovi messaggi?
    Occhio che a questo punto nel client dovrai gestirti l'accesso delle risorse in concorrenza, e le tue risorse sono il socket verso il server e la bacheca dei messaggi.
    ...

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.