Jump to content

[Java] Serialisation et Socket non bloquantes.


lmarin

Recommended Posts

Bonjour tout le monde,

Alors voila, j'aimerais réaliser un serveur qui permettrais a des clients java d'obtenir des objets sérialiser que le serveur est allé cherchez sur une base de données local.

Coté serveur, j'ai réaliser un petit serveur en socket non bloquante a l'aide de java.nio . Cependant, lorsque je veux sériasliser un objet et passer en le flux de sortie en paramettre, j'ai une belle exception :

java.nio.channels.IllegalBlockingModeException

Voici le bout de code incrimminé :

 ObjectOutputStream outObj = new ObjectOutputStream(clientSock.socket().getOutputStream());

Quelqu'un aurais t il une idée?

Merci

Link to comment
Share on other sites

passe par un String intermédiaire.

tu construis ton ObjectOutputStream sur un ByteArrayOutputStream, tu écris ton objet dedans, et tu écris l'array sur le socket.

dse l'autre côté tu lis des ByteArray, et tu les déserialise.

C'est bourrin, mais ça marche :keskidit:

Link to comment
Share on other sites

L'interet des socket asynchrones c'est de justement se passer des stream non ? :-)

En nio (comme dans toutes les api qui utilisent le select() pour gerer les sockets ) tu dois allouer un buffer de réception que le channel devra remplir apres sa notification.

On alloue d'abord le buffer de réception avec :

ByteBuffer buffer = ByteBuffer.allocate(1024); // ou allocateDirect je crois qu'il est plus rapide car il appele des interfaces natives

La taille est figée, au lieu d'attendre que le peer se déconnecte ou que le terminator ait eu lieu avec les stream.

Ensuite pour la réception dans le key.isReadable() un simple :

len = channel.read(buffer);

qui remplit le buffer de réception avec des bytes que tu pourras utiliser dans un ByteArrayOutputStream comme a dit lorinc.

Enfin l'interet d'attendre l'information est pas trop logique avec nio, enfin on attend pas une information destinée à arriver toute seule.

Link to comment
Share on other sites

Voici les deux fichiers de codes....

Le serveurs en soit...

import java.io.IOException;
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import java.sql.SQLException;
import java.util.*;
import LmarinLib.SQL.*;

public class Serveur {

private int port;
private ByteBuffer buffer;
public static Sql lienSql;
private String url = "jdbc:mysql://193.3.1.7/Kalent_db";
//public static String url = "jdbc:mysql://localhost/Kalent_db";
private String driverSql = "com.mysql.jdbc.Driver";

public Serveur(int port) throws IOException {
	this.port = port;
	buffer = ByteBuffer.allocateDirect(1024);
	System.out.print("#### Vérification de la connection a la Base de donnée");
	lienSql = new Sql(driverSql,"kalentConnect","Connect",url);
	try {
		if(lienSql.connecter()){
			System.out.println(" ... OK ####");
			lienSql.fermerLink();
		}
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	} catch (SQLException e) {
		e.printStackTrace();
	}
	System.out.print("#### Lancement du Serveur :"+this.port+" ####");
	ServerSocketChannel serverChannel = ServerSocketChannel.open();
	ServerSocket serverSocket = serverChannel.socket();
	Selector selecteur = Selector.open();
	serverSocket.bind(new InetSocketAddress(this.port));
	serverChannel.configureBlocking(false);
	SelectionKey keyServer = serverChannel.register(selecteur,SelectionKey.OP_ACCEPT);
	System.out.println(" ... OK");

	while(true){

		int n = selecteur.select();
		if( n == 0 ) continue;
		Iterator it =  selecteur.selectedKeys().iterator();
		while(it.hasNext()){
			SelectionKey key = ( SelectionKey ) it.next();
			if( key.isAcceptable() ) { //&& key != keyServer){
				System.out.println("# -> Nouveau Client");
				ServerSocketChannel server = ( ServerSocketChannel) key.channel();
				SocketChannel channel = server.accept();
				channel.configureBlocking(false);
				SelectionKey keyClient = channel.register(selecteur,SelectionKey.OP_READ | SelectionKey.OP_WRITE,null);
				keyClient.attach(new MysqlIoObject());


			}

//				Lecture sur Socket
			if( key.isReadable() && key.isWritable() ){ // && key != keyServer ){
				MysqlIoObject handler = ( MysqlIoObject ) key.attachment();
				handler.lire(key);
			}

			it.remove();
		}

	}
}

}

L'objet MysqlIoOnject attacher :

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.sql.SQLException;
import java.util.Vector;

import LmarinLib.Lib;
import LmarinLib.SQL.Sqlable;


/*
* Créé le 19 oct. 2006
*/

/**
* @author jpascal
*
*/
public class MysqlIoObject implements Clientable , MysqlSerial {

	private SelectionKey key;
	private Lib lib;

	public MysqlIoObject(){
		this.lib = new Lib();
	}

/**
 * @see MysqlIoObject#insertObject(Sqlable)
 */
public void insertObject(Sqlable obIn) {
	try {
		if (Serveur.lienSql.connecter()) {
			Serveur.lienSql.executer(obIn.inserer());
			Serveur.lienSql.fermerLink();
		}
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	} catch (SQLException e) {
		e.printStackTrace();
	}
}

/**
 * @see MysqlSerial#getObject(java.lang.String)
 */
public Vector getObject(String requete) {
	Vector tmp = null;
	try {
		if (Serveur.lienSql.connecter()) {
			tmp = Serveur.lienSql.getTab(requete);
			Serveur.lienSql.fermerLink();
		}
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	} catch (SQLException e) {
		e.printStackTrace();
	}

		return tmp;

}

/**
 * @throws IOException
 * @see Clientable#lire(java.nio.channels.SelectionKey)
 */
public void lire(SelectionKey key) throws IOException {
	//System.out.println("# Lecture Flux");
	ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
	Charset charset = Charset.forName("ISO-8859-1");
	CharsetEncoder encoder = charset.newEncoder();
	CharsetDecoder decoder = charset.newDecoder();

	SocketChannel clientSock = ( SocketChannel ) key.channel();


   int nbLu = clientSock.read(buffer); 
   if ( nbLu == -1 ) {
	   key.cancel();
	   clientSock.close();
	   System.out.println("Déconnection Client !");
   } else {
	   buffer.flip();
	   String requete = decoder.decode(buffer).toString();
	   buffer.clear();
	   System.out.println("# ->"+requete.trim());

	   String [] commande = this.lib.tok(requete,":");
	   if( commande.length > 1 && commande[1] != null ){
		   if( commande[0].trim().equalsIgnoreCase("GETOBJECTS")){
			   // Demande d'une  collection d'object
			   //
			   System.out.println("#Objet request by Client!");

			   clientSock.write(encoder.encode(CharBuffer.wrap("REQUEST OBJECT OK")));
			   ObjectOutputStream outObj = new ObjectOutputStream(clientSock.socket().getOutputStream());
			   outObj.writeObject(this.getObject(commande[1]));
			   outObj.writeObject(new String("Coucou"));
			   outObj.reset();

		   } else if( commande[0].trim().equalsIgnoreCase("SENDOBJECT")){
			   // Envoi d'objet a inserer.
			  // clientSock.
			   clientSock.write(encoder.encode(CharBuffer.wrap("SENDOBJECT OK")));
			   ObjectInputStream inObj = new ObjectInputStream(clientSock.socket().getInputStream());
			   try {
				Sqlable obj = ( Sqlable ) inObj.readObject();
				this.insertObject(obj);
				} catch (IOException e) {
					e.printStackTrace();
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			  //  clientSock.configureBlocking(false);


		   }
	   }
   }
}

/**
 * @see Clientable#ecrire(java.nio.channels.SelectionKey, java.lang.String)
 */
public void ecrire(SelectionKey key, String txt) {
}

}

Link to comment
Share on other sites

Bon je n'ai pas testé le code mais je vois un probleme sur la lecture, en effet ici :

clientSock.write(encoder.encode(CharBuffer.wrap("REQUEST OBJECT OK")));
ObjectOutputStream outObj = new ObjectOutputStream(clientSock.socket().getOutputStream());

Tu passes la socketChannel en OP_WRITE et tout de suite apres tu lui demande la réponse sans passer par le selector avec le clientSock.socket().getOutputStream() ce qui en effet bloque la socket en réception.

Tu devrais ajouter une clause en plus dans le handler que tu attaches à la socket qui gere les états de la transaction (enfin c'est une idée mais tu geres comme tu le sens :-) genre si tu préferes un annuaire ou autre) mais tant que la socket aura pas changé son état en OP_READ tu ne pourras pas la lire car elle sera bloquée en attente du stream.

Il te faudra quelques boucles supplémentaire sur le selector et attendre que l'état de la socket permette la lecture, sinon il te jetera encore cette exception.

Link to comment
Share on other sites

  • 2 weeks later...

J'ai finalement opter pour une solution un peu plus compliqué, mais qui peux fonctionner.

Actuellement, je colles un handler a ma SelectionKeys avec la focntion attache.

cette objet est lui meme composer d'un objet message ( il me permet de convertir un objet pour pouvoir le serialiser dans un buffer ).

L'objet message est aussi présant chez le client, le seul gros hic, c'est que lorsque que mon client envoi mon message en ByteBuffer, j'arrive pas a le désérialiser de l'autre coté ....

:)

Donc pour résumer, je voulais savoir comment on fait pour désérialiser a partir d'un ByteBuffer.

Merci

PS : Voici le bout de code que j'ai trouver pour le moment, mais il me jette encore une fois une erreur.

int nbLu = clientSock.read(this.buffer); 
   if ( nbLu == -1 ) {
	   key.cancel();
	   clientSock.close();
	   System.out.println("Déconnection Client !");
   } else {

	   System.out.println("# Lecture Flux 1");

	   ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(this.buffer.array()));
}

Voici l'erreur :

java.lang.UnsupportedOperationException
at java.nio.ByteBuffer.array(Unknown Source)

A priori il aime pas le this.buffer.array();

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...