m0linas
17-11-2010, 11:57
Ciao a tutti, devo farvi una domanda riguardo alle Socket, perchè nonostante ci abbia provato e riprovato veramente non riesco a capire....
So che si può comunicare in entrambe le direzioni sulla stessa socket, ma nel mio programma non riesco in nessun modo a farlo....bisogna che le letture/scritture avvengano all'interno dello stesso ciclo (:fagiano:) ?
Vi spiego in 2 parole...ho creato un programma molto rozzo di file sharing p2p per un esame all'università, e funziona. Il problema è che per aggiornare le liste dei file (client invia la lista dei files locali da condividere, e il server gli rimanda indietro la lista completa dei files disponibili) mi tocca usare 2 socket diverse, una per l'invio e una per la ricezione.
La cosa è decisamente brutta, e vorrei che tutto avvenisse sulla stessa socket, dato che da quanto ho capito la cosa si può fare....
In pratica il client manda la lista sulla socket, il server legge dalla socket la lista, la appende alla lista che già possiede, e rimanda quest'ultima (tramite la stessa socket) al client, che la legge e me la visualizza in una JList.
Il problema è la parte in neretto, tutto il resto funziona tranquillamente....
Questo è il metodo lato client:
public void inviaLista()
{
Socket s = null;
try {
s = new Socket();
s.connect(new InetSocketAddress(ip, port));
s.setSoTimeout(timeout);
if (!listaLocali.isEmpty()) listaLocali.clear(); // elimino la vecchia lista e la creo nuova
salvaLista(new File(".")); // verranno condivisi solamente i file nella cartella corrente
BufferedOutputStream bout = new BufferedOutputStream(s.getOutputStream());
ObjectOutputStream out = new ObjectOutputStream(bout);
for (int i=0;i<listaLocali.size();i++)
{
out.writeObject(listaLocali.get(i));
}
// prende indietro la lista
ObjectInputStream inLista = new ObjectInputStream(new BufferedInputStream(s.getInputStream()));
FileProva infl = (FileProva)inLista.readObject();
try
{
while (infl != null)
{
synchronized(listaFiles)
{
listaFiles.add(infl);
}
infl = (FileProva)inLista.readObject();
}
}catch (EOFException eof) {}
synchronized(listaFiles)
{
for (int i=0;i<listaFiles.size();i++)
{
listmodel.addElement(listaFiles.get(i));
}
}
lista.setModel(listmodel);
lista.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
lista.setLayoutOrientation(JList.VERTICAL);
lista.setVisibleRowCount(-1);
inLista.close();
out.flush();
bout.flush();
out.close();
s.close();
} catch (IOException ee) {System.out.println("Errore del client!" ); ee.printStackTrace();}
catch (ClassNotFoundException cnfe) {cnfe.printStackTrace();}
}
Questo è il thread sul server col quale il metodo precedente comunica:
public void run()
{
try
{
BufferedInputStream bin = new BufferedInputStream(s.getInputStream());
ObjectInputStream in = new ObjectInputStream(bin);
InetAddress client = s.getInetAddress();
synchronized(ServerProva.filesArray)
{
for (int pd=0;pd<ServerProva.filesArray.size();pd++)
{
if (ServerProva.filesArray.get(pd).getOwner().equals(client))
{
ServerProva.filesArray.remove(pd);
pd--;
}
}
}
FileProva inFile = (FileProva)in.readObject();
try
{
while (inFile != null)
{
synchronized(ServerProva.filesArray)
{
ServerProva.filesArray.add(inFile);
inFile = (FileProva)in.readObject();
}
}
}catch (EOFException eof) {}
// Invia al client la lista completa dei files disponibili
// sulla rete
BufferedOutputStream bout = new BufferedOutputStream(s.getOutputStream());
ObjectOutputStream outLista = new ObjectOutputStream(bout);
synchronized(ServerProva.filesArray)
{
for (int i=0;i<ServerProva.filesArray.size();i++)
{
FileProva f = ServerProva.filesArray.get(i);
outLista.writeObject(f);
}
}
in.close();
bout.flush();
outLista.flush();
outLista.close();
s.close();
} catch (InterruptedIOException e) {System.out.println("Timeout in ServerThread");e.printStackTrace();}
catch (IOException ee) {System.out.println("Errore di IO in ServerThread");ee.printStackTrace();}
catch (ClassNotFoundException cnfe) {cnfe.printStackTrace();}
}
E questo è l'errore che mi becco:
Errore del client!
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:258)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at java.io.ObjectInputStream$PeekInputStream.read(ObjectInputStream.java:2266)
at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2279)
at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:2750)
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:780)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:280)
at ClientProva.inviaLista(ClientProva.java:128)
at ClientProva.aggiorna(ClientProva.java:167)
at ClientProva.main(ClientProva.java:202)
Nel lato client, se chiudo lo stream in uscita appena ho scritto sulla socket, quando vado a fare s.getInputStream mi dice
java.net.SocketException: Socket is closed
at java.net.Socket.getInputStream(Socket.java:788)
at ClientProva.inviaLista(ClientProva.java:131)
at ClientProva.aggiorna(ClientProva.java:168)
at ClientProva.main(ClientProva.java:203)
Errore di IO in ServerThread
java.net.SocketException: Socket closed
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:99)
at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
at ServerThread.run(ServerThread.java:75)
In pratica se chiudo subito uno dei 2 stream dello stesso processo, l'altro vede chiusa proprio la socket, se non li chiudo si pianta tutto e va in timeout....
É una settimana che il programma sarebbe finito, tranne per questa cagata qui....sarò infinitamente grato a chi mi risolve l'arcano!
So che si può comunicare in entrambe le direzioni sulla stessa socket, ma nel mio programma non riesco in nessun modo a farlo....bisogna che le letture/scritture avvengano all'interno dello stesso ciclo (:fagiano:) ?
Vi spiego in 2 parole...ho creato un programma molto rozzo di file sharing p2p per un esame all'università, e funziona. Il problema è che per aggiornare le liste dei file (client invia la lista dei files locali da condividere, e il server gli rimanda indietro la lista completa dei files disponibili) mi tocca usare 2 socket diverse, una per l'invio e una per la ricezione.
La cosa è decisamente brutta, e vorrei che tutto avvenisse sulla stessa socket, dato che da quanto ho capito la cosa si può fare....
In pratica il client manda la lista sulla socket, il server legge dalla socket la lista, la appende alla lista che già possiede, e rimanda quest'ultima (tramite la stessa socket) al client, che la legge e me la visualizza in una JList.
Il problema è la parte in neretto, tutto il resto funziona tranquillamente....
Questo è il metodo lato client:
public void inviaLista()
{
Socket s = null;
try {
s = new Socket();
s.connect(new InetSocketAddress(ip, port));
s.setSoTimeout(timeout);
if (!listaLocali.isEmpty()) listaLocali.clear(); // elimino la vecchia lista e la creo nuova
salvaLista(new File(".")); // verranno condivisi solamente i file nella cartella corrente
BufferedOutputStream bout = new BufferedOutputStream(s.getOutputStream());
ObjectOutputStream out = new ObjectOutputStream(bout);
for (int i=0;i<listaLocali.size();i++)
{
out.writeObject(listaLocali.get(i));
}
// prende indietro la lista
ObjectInputStream inLista = new ObjectInputStream(new BufferedInputStream(s.getInputStream()));
FileProva infl = (FileProva)inLista.readObject();
try
{
while (infl != null)
{
synchronized(listaFiles)
{
listaFiles.add(infl);
}
infl = (FileProva)inLista.readObject();
}
}catch (EOFException eof) {}
synchronized(listaFiles)
{
for (int i=0;i<listaFiles.size();i++)
{
listmodel.addElement(listaFiles.get(i));
}
}
lista.setModel(listmodel);
lista.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
lista.setLayoutOrientation(JList.VERTICAL);
lista.setVisibleRowCount(-1);
inLista.close();
out.flush();
bout.flush();
out.close();
s.close();
} catch (IOException ee) {System.out.println("Errore del client!" ); ee.printStackTrace();}
catch (ClassNotFoundException cnfe) {cnfe.printStackTrace();}
}
Questo è il thread sul server col quale il metodo precedente comunica:
public void run()
{
try
{
BufferedInputStream bin = new BufferedInputStream(s.getInputStream());
ObjectInputStream in = new ObjectInputStream(bin);
InetAddress client = s.getInetAddress();
synchronized(ServerProva.filesArray)
{
for (int pd=0;pd<ServerProva.filesArray.size();pd++)
{
if (ServerProva.filesArray.get(pd).getOwner().equals(client))
{
ServerProva.filesArray.remove(pd);
pd--;
}
}
}
FileProva inFile = (FileProva)in.readObject();
try
{
while (inFile != null)
{
synchronized(ServerProva.filesArray)
{
ServerProva.filesArray.add(inFile);
inFile = (FileProva)in.readObject();
}
}
}catch (EOFException eof) {}
// Invia al client la lista completa dei files disponibili
// sulla rete
BufferedOutputStream bout = new BufferedOutputStream(s.getOutputStream());
ObjectOutputStream outLista = new ObjectOutputStream(bout);
synchronized(ServerProva.filesArray)
{
for (int i=0;i<ServerProva.filesArray.size();i++)
{
FileProva f = ServerProva.filesArray.get(i);
outLista.writeObject(f);
}
}
in.close();
bout.flush();
outLista.flush();
outLista.close();
s.close();
} catch (InterruptedIOException e) {System.out.println("Timeout in ServerThread");e.printStackTrace();}
catch (IOException ee) {System.out.println("Errore di IO in ServerThread");ee.printStackTrace();}
catch (ClassNotFoundException cnfe) {cnfe.printStackTrace();}
}
E questo è l'errore che mi becco:
Errore del client!
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:258)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at java.io.ObjectInputStream$PeekInputStream.read(ObjectInputStream.java:2266)
at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2279)
at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:2750)
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:780)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:280)
at ClientProva.inviaLista(ClientProva.java:128)
at ClientProva.aggiorna(ClientProva.java:167)
at ClientProva.main(ClientProva.java:202)
Nel lato client, se chiudo lo stream in uscita appena ho scritto sulla socket, quando vado a fare s.getInputStream mi dice
java.net.SocketException: Socket is closed
at java.net.Socket.getInputStream(Socket.java:788)
at ClientProva.inviaLista(ClientProva.java:131)
at ClientProva.aggiorna(ClientProva.java:168)
at ClientProva.main(ClientProva.java:203)
Errore di IO in ServerThread
java.net.SocketException: Socket closed
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:99)
at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
at ServerThread.run(ServerThread.java:75)
In pratica se chiudo subito uno dei 2 stream dello stesso processo, l'altro vede chiusa proprio la socket, se non li chiudo si pianta tutto e va in timeout....
É una settimana che il programma sarebbe finito, tranne per questa cagata qui....sarò infinitamente grato a chi mi risolve l'arcano!