View Full Version : [JAVA] Passaggio oggetti tramite DatagramPacket
franksisca
08-06-2010, 14:52
come ricostruisco l'oggetto che ho passato tramite una datagrampacket al server?
mi spiego.
sul server creo il mio labirinto 3d, che dfevo inviare a tutti i client in modo che loro possano "giocarlo".
facendo una comunicazione a più cliente e il più veloce possibile, sto usando datagrampacket.
ora, quando ricevo il datagrampacket faccio così:
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
ora...come ricostruisco l'oggetto originale dal packet???
inoltre, come faccio a sapere la dimensione del buffer per evitare troppi "sopacchettamenti"?
franksisca
09-06-2010, 08:51
uppetino?
nuovoUtente86
09-06-2010, 10:35
Penso che tu abbia implementato degli I/O stream in grado di interfacciarsi sulla rete attraverso UDP. Prova a postarne il codice, cosi vediamo.
franksisca
09-06-2010, 11:41
classe client
package online;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import labirinti.Labirinto;
public class Client {
public static void main(String[] args) throws IOException {
MulticastSocket socket = new MulticastSocket(4446);
InetAddress address = InetAddress.getByName("224.0.0.1");
socket.joinGroup(address);
DatagramPacket packet;
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
buf=packet.getData();
boolean flag = true;
while (flag) {
String received = new String(packet.getData(), 0, packet
.getLength());
System.out.println("Quote of the Moment: " + received);
}
socket.leaveGroup(address);
socket.close();
}
}
classe quoteserverthread
package online;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Date;
public class QuoteServerThread extends Thread {
protected DatagramSocket socket = null;
protected BufferedReader in = null;
protected boolean altroTesto = true;
public QuoteServerThread() throws IOException {
this("QuoteServerThread");
}
public QuoteServerThread(String name) throws IOException {
super(name);
socket = new DatagramSocket(4444);
try {
in = new BufferedReader(new FileReader("one-liners.txt"));
} catch (FileNotFoundException e) {
System.err.println("Could not open quote file. Serving time instead.");
}
}
public void run() {
while (altroTesto) {
try {
byte[] buf = new byte[1024];
// receive request
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
// figure out response
String dString = null;
if (in == null)
dString = new Date().toString();
else
dString = getNextQuote();
buf = dString.getBytes();
// send the response to the client at "address" and "port"
InetAddress address = packet.getAddress();
int port = packet.getPort();
packet = new DatagramPacket(buf, buf.length, address, port);
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
altroTesto = false;
}
}
socket.close();
}
protected String getNextQuote() {
String returnValue = null;
try {
if ((returnValue = in.readLine()) == null) {
in.close();
altroTesto = false;
returnValue = "No more quotes. Goodbye.";
}
} catch (IOException e) {
returnValue = "IOException occurred in server.";
}
return returnValue;
}
}
classe server
package online;
public class Server {
public static void main(String[] args) throws java.io.IOException {
new ServerThread(new ServerMakerLabirinto()).start();
}
}
classe servermakerlabirinto
package online;
import labirinti.Labirinto;
import labirinti.LabirintoSemplice;
public class ServerMakerLabirinto {
private Labirinto labirinto;
public ServerMakerLabirinto(){
this.labirinto=new LabirintoSemplice();
}
}
classe server thread
package online;
import java.io.*;
import java.net.*;
import java.util.*;
public class ServerThread extends QuoteServerThread {
private long tempo = 5000;
private ServerMakerLabirinto serverMakerLabirinto;
public ServerThread(ServerMakerLabirinto serverMakerLabirinto) throws IOException {
super("ServerThread");
this.serverMakerLabirinto=serverMakerLabirinto;
}
public void run() {
while (altroTesto) {
try {
byte[] buf = new byte[256];
// construct quote
String dString = null;
if (in == null)
dString = new Date().toString();
else
dString = getNextQuote();
buf = dString.getBytes();
// send it
InetAddress group = InetAddress.getByName("224.0.0.1");
DatagramPacket packet = new DatagramPacket(buf, buf.length,
group, 4446);
socket.send(packet);
// sleep for a while
try {
sleep((long) (Math.random() * tempo));
} catch (InterruptedException e) {
}
} catch (IOException e) {
e.printStackTrace();
altroTesto = false;
}
}
socket.close();
}
}
il funzionamento è "semplice":
il servermaker costruisce il labirinto e lo passa al server.
quando al server arrivano le richieste di 32 player (è un 1v1 il gioco) manda ad entrambi lo stesso labirinto, alchè i client costruiscono il proprio mondo 3d e mandano info continuamente al server che aggiorna il labirinto con le posizioni dei due pg e le rimanda ad entrambi.
credo che la strutura sia corretta, ma non sò come ricostruire il labirinto una volta arrivati sui client
franksisca
10-06-2010, 09:37
up???
stavo pensando, mi dovrei creare un costruttore di labirinto che ricevi un []byte, ma come "cacchio" faccio?
se pensate ad una soluzione diversa sparatemela pls, non ho molto tempo.
nuovoUtente86
10-06-2010, 10:26
Costruisciti un tuo Input/Output stream, che recupera i byte da UDP, e lo agganci ad un Object stream.
franksisca
10-06-2010, 10:30
Costruisciti un tuo Input/Output stream, che recupera i byte da UDP, e lo agganci ad un Object stream.
e come?
mai fatto sinceramente :p
nuovoUtente86
10-06-2010, 10:52
Estendendo le classi astratte InputStream e OutputStream. Considera anche, di aggiungere al tuo protocollo su UDP qualche controllo supplementare, in modo da forzare la ri-spedizione di qualche segmento perso.
franksisca
10-06-2010, 11:22
Estendendo le classi astratte InputStream e OutputStream. Considera anche, di aggiungere al tuo protocollo su UDP qualche controllo supplementare, in modo da forzare la ri-spedizione di qualche segmento perso.
ho trovato un "gioco" simile al mio, solo che usa rmi.
reputi sia più semplice?
o meglio fe come suggerisci tu?
nuovoUtente86
10-06-2010, 14:35
Dipende molto da come intendi strutturare l' applicazione. Con RMI utilizzi gli oggetti remoti come se fossero in locale, quindi ti viene celata tutta la logica di rete che ci sta dietro. Nell' altro caso devi gestire da te il recupero degli oggetti e anche l' aventuale sincronizzazioni tra i "dati" prodotti localmente dai client e il server. Ovviamente cambia anche la distribuzione dei carichi di lavoro.
franksisca
10-06-2010, 15:15
Dipende molto da come intendi strutturare l' applicazione. Con RMI utilizzi gli oggetti remoti come se fossero in locale, quindi ti viene celata tutta la logica di rete che ci sta dietro. Nell' altro caso devi gestire da te il recupero degli oggetti e anche l' aventuale sincronizzazioni tra i "dati" prodotti localmente dai client e il server. Ovviamente cambia anche la distribuzione dei carichi di lavoro.
l'applicazione è già strutturata.
il gioco è nato come "in solo".
ora lo sto estendendo in ulty, 1v1, chi trova l'uscita prima vince.
praticamente il server crea il labirinto e lo comunica ai player, che creano il mondo 3d e lo navigano, comunicando al server la loro posizione continuamente, quindi inviano solo posizione(e non tutto come avevo pensato io prima), ma all'inizio ricevono tutto il labirinto.
il server quando riceve i dati li ricomunica a tutti.
cosa mi consigli di usare?
rmi forse è eccessivo in questa ottiva, vero?
e se usassi OBJECTOUTPUTSTREAM???
ho trovato un pdf che ne parla, me lo sto studiando.
nuovoUtente86
10-06-2010, 15:26
Un' architettura ibrida? Nel senso che il gioco lo gestisci (una volta acquisito su ogni client il necessario) in locale su ogni client, come è giusto che sia, mentre la sincronizzazione tra i vari partecipanti, la fai in RMI in modo da gestirla, abbastanza agevolmente, come un' applicazione multi-thread sul server.
nuovoUtente86
10-06-2010, 15:27
e se usassi OBJECTOUTPUTSTREAM???ne avevo parlato all' inizio: lo utilizzi per recuperare gli oggetti che ti servono su ogni client.
franksisca
10-06-2010, 15:35
Un' architettura ibrida? Nel senso che il gioco lo gestisci (una volta acquisito su ogni client il necessario) in locale su ogni client, come è giusto che sia, mentre la sincronizzazione tra i vari partecipanti, la fai in RMI in modo da gestirla, abbastanza agevolmente, come un' applicazione multi-thread sul server.
si, ma credo che farlo con rmi sia troppo dispendioso (almeno questo mi passa per la testa ora)...ovvero, rmi lo vedo bello potente e questa cosa non mi sembra richieda tutta questa potenza...
ne avevo parlato all' inizio: lo utilizzi per recuperare gli oggetti che ti servono su ogni client.
si, ma io non avevo capito :p
per info metto qui la dispensa, magari serve ad altri:
http://issuu.com/franksisca/docs/invio_oggetti_udp_java
nuovoUtente86
10-06-2010, 17:31
RMI è abbastanza potente, ma nel complesso non è affatto difficile implementare una buona struttura, anche perchè come ti dicevo ti concentreresti più sulla logica che sui dettagli del protocollo.
In alternativa, pur non conoscendo la mole di dati che transiterebbe sulla rete, mi viene in mente un sistema basato su UDP con Nack temporizzati(e magari gestione della mancanza temporanea di dati). In questo modo sarebbe il server a richiedere i dati in caso di mancata consegna. In tal modo aumenta la complessità e il carico computazionale del server, ma produci meno overhead di rete.
franksisca
16-06-2010, 10:24
alora, ho fatto così:
client
package online;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import labirinti.LabirintoSemplice;
public class Client {
private InetAddress indirizzoIP;
private MulticastSocket datagramSocket;
private DatagramPacket datagramPacket;
private ByteArrayInputStream byteData;
private ByteArrayOutputStream byteOutput;
private ObjectInputStream objectInput;
private ObjectOutputStream objectOutput;
public void start() {
try {
int port = 1300;
// invio informazione al server della connessione avvenuta
byte buffer[] = new byte[256];
this.indirizzoIP = InetAddress.getByName("LocalHost");
this.datagramSocket = new MulticastSocket(port);
this.datagramSocket.joinGroup(this.indirizzoIP);
this.byteOutput = new ByteArrayOutputStream();
this.datagramPacket = new DatagramPacket(buffer, buffer.length,
this.indirizzoIP, port);
this.objectOutput = new ObjectOutputStream(this.byteOutput);
this.objectOutput.writeObject("sono connesso");
// ricevo dal server il labirinto in cui muovermi
this.datagramPacket = new DatagramPacket(buffer, buffer.length);
this.datagramSocket.receive(this.datagramPacket);
this.byteData = new ByteArrayInputStream(this.datagramPacket
.getData());
this.objectInput = new ObjectInputStream(this.byteData);
LabirintoSemplice labirinto = (LabirintoSemplice) this.objectInput
.readObject();// ricevo il labirinto e costruisco l'ambiente
// grafico
AmbienteOnlineClient ambienteClient = new AmbienteOnlineClient(
labirinto);
while (true) {// fino a quando qualcuno non vince
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
server:
package online;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class ServerThread extends QuoteServerThread {
private ServerMakerLabirinto serverMakerLabirinto;
private MulticastSocket multicastSocket;
private ByteArrayOutputStream byteOutput;
private DatagramPacket pacchetto;
private ByteArrayInputStream byteData;
private ObjectOutputStream objectOutput;
private ObjectInputStream objectInput;
private InetAddress indirizzoIP;
public ServerThread(ServerMakerLabirinto serverMakerLabirinto)
throws IOException {
super("ServerThread");
this.serverMakerLabirinto = serverMakerLabirinto;
}
public void run() {
try {
this.indirizzoIP = InetAddress.getByName("LocalHost");
int port = 1300;
this.multicastSocket = new MulticastSocket();
byte[] data = new byte[1024];
int cnt = 0;
while (cnt < 2) {// aspetto i 2 client connessi
this.pacchetto = new DatagramPacket(data, data.length);
this.multicastSocket.receive(this.pacchetto);
this.byteData = new ByteArrayInputStream(this.pacchetto
.getData());
this.objectInput = new ObjectInputStream(this.byteData);
this.objectInput.readObject();
cnt++;
}
// i 2 client sono connessi, quindi invio ad entrambi il labiritno
// costruito senza mostri
this.byteOutput = new ByteArrayOutputStream();
this.pacchetto = new DatagramPacket(data, data.length,
this.indirizzoIP, port);
this.objectOutput = new ObjectOutputStream(this.byteOutput);
this.objectOutput.writeObject(this.serverMakerLabirinto
.getLabirinto()); // invio il labirinto ai client
this.objectOutput.flush();
data = this.byteOutput.toByteArray();
this.pacchetto.setData(data);
this.pacchetto.setLength(data.length);
this.multicastSocket.send(this.pacchetto);
this.byteOutput.reset();
while (true) {// ricevo i labirinti dai client e li reinvio
}
} catch (Exception e) {
}
}
}
credete che sia valida come soluzione?
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.