Bonjour tout le monde,
J'essaye de recréer un serveur "style" RMI avec des sockets mais mon projet me retourne une exception:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
[Serializer.deserialize] java.lang.reflect.Method
java.lang.NullPointerException
	at java.base/java.io.DataOutputStream.writeUTF(DataOutputStream.java:347)
	at java.base/java.io.DataOutputStream.writeUTF(DataOutputStream.java:323)
	at server.ClientConnexion.send(ClientConnexion.java:31)
	at server.ClientConnexion.send(ClientConnexion.java:25)
	at server.LoggingHandler.invoke(LoggingHandler.java:18)
	at com.sun.proxy.$Proxy0.display(Unknown Source)
	at main.Main.<init>(Main.java:39)
	at main.Main.main(Main.java:34)
Alors, il y a beaucoup de choses mais voila comment il fonctionne côté serveur:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
public class ServerStarter {
	Server server = new Server();
	public static void main(String[] args) { new ServerStarter(); }
}
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class Server extends Thread{
 
	private ServerSocket serverSocket;
	private int port;
	private transient HashMap<String, ServerConnection> connections = new HashMap<String, ServerConnection>();
 
	public int getPort() { return this.port; }
 
	public Server(){  this(1900); }
	public Server(int port){ 
		this.port = port;
		try { 
			UPnP.openPortTCP(port);
			serverSocket = new ServerSocket(port);
			System.out.println("Server launched");
			this.start();
		}catch (Exception e) { System.err.println("[Server] " + e.getMessage()); }
	}
 
	public void run(){
		try { 
			while(!serverSocket.isClosed()){
				ServerConnection c = new ServerConnection(serverSocket.accept());
				this.connections.put(c.getClientIP(), c);
			}
		}catch (Exception e) { System.err.println("[Server Run] " + e.getMessage()); }
	}
 
	public void close(){ 
		try { 
			UPnP.closePortTCP(port);
			serverSocket.close();
			for(Map.Entry<String, ServerConnection> e : connections.entrySet()){
				e.getValue().close();
			}
			System.out.println("Server closed");
		}catch (Exception e) { System.err.println("[Server Close] " + e.getMessage()); }
	}
 
}
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class ServerConnection extends Thread{
 
	private Socket socket;
	private DataInputStream dataInputStream;
	private DataOutputStream dataOutputStream;
	private Object target;
 
	public String getClientIP(){ return socket.getRemoteSocketAddress().toString(); }
 
	protected ServerConnection(Socket socket){
		try { 
			this.socket = socket;
			this.dataInputStream = new DataInputStream(socket.getInputStream());
			this.dataOutputStream = new DataOutputStream(socket.getOutputStream());
			this.start();
		}catch (Exception e) { System.err.println("[Connection] " + e.getMessage()); }
	}
 
	public void run(){
		try{ 
			target = Serializer.deserializeString(dataInputStream.readUTF());
			while(true){
				Package pack = (Package) Serializer.deserializeString(dataInputStream.readUTF());
				pack.setTarget(target);
				dataOutputStream.writeUTF(Serializer.serializeString(pack.invokeMethod()));
			} 
		}catch (Exception e) { 
			e.printStackTrace();
		} 
	}
 
	public void close(){
		try {
			dataInputStream.close();
			dataOutputStream.close();
			socket.close();
		}catch(Exception e){ e.printStackTrace(); }
	}
 
}
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Package implements Serializable{
 
	private Object target;
	private final Method method;
	private final Object[] args;
 
	public void setTarget(Object target) {
		this.target = target;
	}
 
	public Package(Object target, Method method, Object[] args) {
		this.method = method;
		this.args = args;
	}
 
	public Serializable invokeMethod() {
		try {
			return (Serializable) method.invoke(target, args);
		} catch (Exception e) { e.printStackTrace(); }
		return null;
	}
}
Pour résumer, à chaque fois qu'un client veut créé un objet distant, il créé une connexion.
A ce moment le serveur créé un objet ServerConnection qui contient un objet target qui est l'objet distant.
Donc, quand le client appellera une fonction de l'objet, l'appel sera détourné vers le serveur sous forme de Package.
Le serveur exécute la fonction sur target et renvoi le résultat au client.
Voila le côté client:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
public class ClientStarter {
	Client client = new Client("176.159.75.95" ,1900);
	Player player = (Player) client.getRemote(new PlayerDefinition());
	public static void main(String[] args) { new ClientStarter(); }
	public ClientStarter() { player.display();}
}
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
public interface Player extends Serializable{
	public void setLocation(Point2D p);
	public void display();
}
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
public class PlayerDefinition extends Point2D.Double implements Player{
 
	public PlayerDefinition(double x, double y) { super(x, y); }
	public PlayerDefinition() { super(50, 50); }
	@Override
	public void display() {
		System.out.println(x + " " + y);
	}
 
}
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Client{
 
	private final String address;
	private final int port;
 
	public Client(String address, int port){
		this.address = address;
		this.port = port;
		UPnP.openPortTCP(port);
	}
 
	public Serializable getRemote(Serializable target) {
		ClientConnexion connexion = new ClientConnexion(address, port, target);
		Class<?>[] c = target.getClass().getInterfaces();
		return (Serializable) Proxy.newProxyInstance(c[0].getClassLoader(), c, new LoggingHandler(target, connexion));
	}
 
}
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class ClientConnexion {
	private Socket socket;
	private DataInputStream dataInputStream;
	private DataOutputStream dataOutputStream;
 
	public ClientConnexion(String address, int port, Serializable target){
		try{
			this.socket = new Socket(address, port);
			this.dataInputStream = new DataInputStream(socket.getInputStream());
			this.dataOutputStream = new DataOutputStream(socket.getOutputStream());
			this.dataOutputStream.writeUTF(Serializer.serializeString(target));
		}catch(Exception e){ e.printStackTrace(); }
	}
 
	public Object send(Serializable message){
		return this.send(Serializer.serializeString(message));
	}
 
	public Object send(String string){
		try { 
			if(!socket.isClosed() && !socket.isInputShutdown()){
				this.dataOutputStream.writeUTF(string);
				return (Object) this.dataInputStream.readUTF();
			}
		}catch(Exception e){ e.printStackTrace(); }
		return null;
	}
 
	public void close(){
		try {
			if(socket.isConnected()){ socket.close(); }
		}catch(Exception e){ e.printStackTrace(); }
	}
}
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class LoggingHandler implements InvocationHandler{
 
	private final Object target;
	private ClientConnexion client;
 
	public LoggingHandler(Object target, ClientConnexion client) {
		this.target = target;
		this.client = client;
	}
 
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if(client != null) {
			return client.send(new Package(target, method, args));
		}
		return null;
	}
 
}
Player est mon objet distant, donc j'utilise Client pour créé un proxy qui dérivera les appels de fonction vers le serveur.
Tout ce passe dans client.getRemote() qui créé une connexion et envoi la target au serveur.
Ensuite il créé le proxy que l'on défini dans l'InvocationHandler ou l'on envoi, au serveur, l'appel de la méthode dans un Package.
Le serveur traitera l'information et retournera un résultat que l'on return coté client, comme si la fonction était exécutée en local.

Voilà, c'est un peut lourd, j'en suis désolé.
Merci beaucoup de votre aide.