Ciao!
Sto cercando di creare un programma che implementi il gioco del tris con protocollo client/server che abbia un interfaccia grafica.
L'idea di base è questa: per l'interfaccia grafica, uso una griglia 3x3 di JButton, ognuno con un proprio listener che, all'atto della pressione, inviano una stringa al server relativa alla posizione del pulsante stesso ("1-1" pulsante in alto a sinistra, "1-3" pulsante in alto a destra ecc. ecc.). Il server, ricevuta la stringa, invia la stringa X o O a tutti i client (compreso quello che ha effettivamente inoltrato il messaggio) che, infine, dovrebbero aggiornare il rispettivo JButton con la stringa ricevuta.
Il problema è il seguente: il protocollo per lo scambio dei messaggi funziona correttamente solo se elimino tutta la parte grafica (cioè, come se volessi realizzare lo stesso programma senza utilizzare finestre, actionListener ecc. ecc.). Includendola, infatti, all'atto della pressione del pulsante in alto a sinistra (non importa se nella finestra del giocatore 1 o 2), quella particolare finestra si blocca e il programma non va avanti.
Il codice che ho svolto finora è questo:
- Lato server - : ho creato un array che tiene traccia delle due connessioni massime effettuabili e, per ognuna di esse, viene fatto partire un thread. Per adesso, ho implementato solo il codice relativo alla ricezione della stringa "1-1" da parte del client.
codice:
import java.io.*;
import java.net.*;
public class TrisServer
{
static final int MAX_CONNECTIONS = 2;
static InputOutputServer[] giocatori = new InputOutputServer[2];
public static void main (String[] args)
{
try
{
boolean giocatore1 = false;
boolean giocatore2 = false;
int connessioni = 0;
ServerSocket s = new ServerSocket(8089);
System.out.println ("In ascolto sulla porta 8089...");
while (true)
{
if (connessioni<MAX_CONNECTIONS)
{
Socket incoming = s.accept();
System.out.println ("Collegato!");
if ((giocatore1 == false) && (giocatore2 == false))
{
giocatore1 = true;
}
else if ((giocatore1==true) && (giocatore2==false))
{
giocatore2 = true;
}
else if ((giocatore2==true) && (giocatore1==false))
{
giocatore1 = true;
}
giocatori[connessioni] = new InputOutputServer (incoming, giocatori);
Runnable r = giocatori[connessioni];
Thread t = new Thread (r);
t.start();
connessioni++;
System.out.println ("Connessioni correnti: "+connessioni);
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
import java.io.*;
import java.net.*;
import java.util.*;
public class InputOutputServer implements Runnable
{
private Socket incoming;
private InputOutputServer[] players;
private boolean tGiocatore1;
private boolean tGiocatore2;
private PrintWriter out;
private Scanner in;
private String name;
public InputOutputServer(Socket incoming, InputOutputServer[] giocatori)
{
this.incoming = incoming;
players = giocatori;
}
public void run()
{
try
{
try
{
InputStream inStream = incoming.getInputStream();
OutputStream outStream = incoming.getOutputStream();
in = new Scanner (inStream);
out = new PrintWriter(outStream, true);
boolean done = false;
tGiocatore1 = true;
tGiocatore2 = false;
out.println ("Scrivi il nome: ");
if (in.hasNextLine())
name = in.nextLine();
System.out.println ("Ho ricevuto il nome "+name);
while (!done && in.hasNextLine())
{
String line;
System.out.println ("Aspetto mossa giocatore");
line = in.nextLine();
if (line.equals("1-1"))
{
if (tGiocatore1 == true)
{
for (int i=0; i<players.length; i++)
{
System.out.println ("Invio X a: "+players[i].name);
players[i].out.println ("X");
}
tGiocatore1 = false;
tGiocatore2 = true;
}
}
}
finally
{
incoming.close();
in.close();
out.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
- Lato client - anche qui, ho implementato solo il codice del listener relativo alla casella11.
codice:
import java.awt.*;
import java.io.*;
import java.net.*;
public class TrisClient
{
static Socket clientSocket;
static int numeroPorta = 8089;
static String host = "localhost";
public static void main (String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
clientSocket = new Socket (host, numeroPorta);
Runnable frame = new TrisFrame(clientSocket);
Thread t = new Thread (frame);
t.start();
}
catch (UnknownHostException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
});
}
}
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.Socket;
import java.util.*;
import javax.swing.*;
public class TrisFrame extends JFrame implements Runnable
{
private static final int LUNGHEZZA = 300;
private static final int LARGHEZZA = 300;
private JPanel panel;
private JButton casella11;
private JButton casella12;
private JButton casella13;
private JButton casella21;
private JButton casella22;
private JButton casella23;
private JButton casella31;
private JButton casella32;
private JButton casella33;
private Socket i;
private String line;
private Scanner in;
private PrintWriter out;
private InputStream inputStream;
private OutputStream outputStream;
private String name;
public TrisFrame (Socket incoming) throws IOException
{
i = incoming;
inputStream = i.getInputStream();
outputStream = i.getOutputStream();
in = new Scanner (inputStream);
out = new PrintWriter(outputStream,true);
Scanner in2 = new Scanner (System.in);
name = in.nextLine();
System.out.println (name);
name = in2.nextLine();
out.println(name);
setTitle ("TIC TAC TOE");
setSize (LUNGHEZZA, LARGHEZZA);
panel = new JPanel();
panel.setLayout(new GridLayout (3,3));
panel.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
casella11 = inizializzaCasella(casella11, panel, new ActionListener()
{
public void actionPerformed (ActionEvent event)
{
out.println("1-1");
System.out.println ("Invio 1-1");
scambioMessaggi();
}
});
casella12 = inizializzaCasella(casella12, panel, new ActionListener()
{
public void actionPerformed (ActionEvent event)
{
casella12.setText("2");
}
});
casella13 = inizializzaCasella(casella13,panel,new ActionListener()
{
public void actionPerformed (ActionEvent event)
{
casella13.setText("3");
}
});
casella21 = inizializzaCasella(casella21,panel,new ActionListener()
{
public void actionPerformed (ActionEvent event)
{
casella21.setText("4");
}
});
casella22 = inizializzaCasella(casella22,panel,new ActionListener()
{
public void actionPerformed (ActionEvent event)
{
casella22.setText("5");
}
});
casella23 = inizializzaCasella(casella23,panel,new ActionListener()
{
public void actionPerformed (ActionEvent event)
{
casella23.setText("6");
}
});
casella31 = inizializzaCasella(casella31,panel,new ActionListener()
{
public void actionPerformed (ActionEvent event)
{
casella31.setText("7");
}
});
casella32 = inizializzaCasella(casella32,panel,new ActionListener()
{
public void actionPerformed (ActionEvent event)
{
casella32.setText("8");
}
});
casella33 = inizializzaCasella(casella33,panel,new ActionListener()
{
public void actionPerformed (ActionEvent event)
{
casella33.setText("9");
}
});
add(panel,BorderLayout.CENTER);
}
private JButton inizializzaCasella (JButton casellaTemp, JPanel panel, ActionListener listener)
{
casellaTemp = new JButton ("");
casellaTemp.setFont(new Font ("Arial", Font.BOLD, 50));
casellaTemp.setBorder(BorderFactory.createLineBorder(Color.BLACK));
casellaTemp.addActionListener(listener);
panel.add(casellaTemp);
return casellaTemp;
}
private void scambioMessaggi ()
{
while (in.hasNextLine())
{
System.out.println ("Entro nel while - Giocatore: "+name);
line = in.nextLine();
System.out.println ("Ho ricevuto dal server: "+line);
casella11.setText(line);
}
System.out.println ("Esco dal while");
}
public void run()
{
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
}
Penso che il problema possa dipendere da questo metodo:
codice:
private void scambioMessaggi ()
{
while (in.hasNextLine())
{
System.out.println ("Entro nel while - Giocatore: "+name);
line = in.nextLine();
System.out.println ("Ho ricevuto dal server: "+line);
casella11.setText(line);
}
System.out.println ("Esco dal while");
}
Infatti, lanciando il programma in esecuzione, la riga "Ho ricevuto dal server: X" viene effettivamente stampata sulla console di output, ma poi il programma si blocca lì. Ho provato a cambiare il while con un if e, effettivamente, l'esecuzione va avanti ma, purtroppo, viene aggiornato solo il JButton della finestra grafica nella quale è stato premuto il pulsante. Altra cosa: controllando con il debugger, ho effettivamente riscontrato che anche l'altro client riceve effettivamente il messaggio dal server, ma non solo il pulsante della sua finestra grafica non si aggiorna, ma non mi vengono nemmeno stampati a schermo i vari messaggi delle println.
Dove sbaglio?
Grazie in anticipo per le risposte.