Java - Selector sockets

 
Vista:

Selector sockets

Publicado por Rocio (13 intervenciones) el 11/02/2009 13:31:18
Hola a todos,

estoy programando una aplicacion cliente/servidor en java 1.5 con selectors.
En mi programa servidor, lo que hago es registrar 2 canales.
Por uno quiero leer lo que me mandan de ese canal, y reenviarlo al otro canal.
Cuando recibo una conexion, me guardo el ServerSocket en una tabla hash, de manera que al leer algo (isReadable), recorro la tabla, y compruebo mi SelectableChannel con los que tengo en la tabla, porque quiero coger el otro canal para escribir en él. Esta comparación es lo que me da problemas.
¿Es esta una forma acertada de escribir por el otro canal? ¿Cómo podría escribir de otra forma?
Si está bien, cómo podria obtener el otro canal?

// PServer.java
import java.io.*;
import java.lang.StringBuffer;
import java.nio.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.nio.charset.*;
import java.net.*;
import java.util.*;
import java.util.HashMap;

import java.util.Iterator;

public class PServer {

int port = 17223; //4001;
Selector selector = null;
ServerSocketChannel selectableChannel = null;
int keysAdded = 0;
HashMap hashMap;
static String QUIT_SERVER = "quit";
static String SHUTDOWN = "shutdown";

public PServer() {
}

public PServer( int port ) {
this.port = port;
}

public void initialize()

throws IOException {
this.selector = SelectorProvider.provider().openSelector();
this.selectableChannel = ServerSocketChannel.open();
this.selectableChannel.configureBlocking(false);
InetSocketAddress isa = new InetSocketAddress(this.port);
this.selectableChannel.socket().bind(isa);



System.out.println("Inicializacion completada");

hashMap = new HashMap();


}



public void finalize()

throws IOException {
this.selectableChannel.close();
this.selector.close();
}

public void acceptConnections() throws IOException, InterruptedException {
System.out.println("Accept connection");
SelectionKey acceptKey = this.selectableChannel.register( this.selector, SelectionKey.OP_ACCEPT );
System.out.println("Despues de registrar");
System.err.println("Acceptor loop..." );

while (( this.keysAdded = acceptKey.selector().select()) > 0 ) {
Set readyKeys = this.selector.selectedKeys();
Iterator i = readyKeys.iterator();

while (i.hasNext()) {
SelectionKey key = (SelectionKey)i.next();
i.remove();
if ( key.isAcceptable() ) {
ServerSocketChannel nextReady = (ServerSocketChannel)key.channel();
System.err.println("Acceptable");
SocketChannel channel = nextReady.accept();
channel.configureBlocking( false );
SelectionKey readKey = channel.register( this.selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE );
readKey.attach( new ChannelCallback( channel ) );
System.err.println("acceptable: "+ channel.toString());
SocketChannel ch=channel.socket().getChannel();
hashMap.put(ch,1);

}

else if ( key.isReadable() ) {
SelectableChannel nextReady = (SelectableChannel) key.channel();
System.err.println("Readable");
this.readMessage( (ChannelCallback) key.attachment() );

Iterator iterator = hashMap.keySet().iterator();
System.err.println(nextReady.toString());
while( iterator. hasNext() ){
System.err.println( iterator.next() );
if (iterator.next()==(SocketChannel)nextReady){
System.err.println("iguales los canales");
}

}



// ChannelCallback callback = (ChannelCallback) key.attachment();
// String message = nextReady.toString();
// System.err.println("mensaje: "+ message);
// System.err.println("cap message:" + message.length());
// ByteBuffer buf = ByteBuffer.wrap( message.getBytes() );
// System.err.println("cap buffer:" + buf.capacity());
// int nbytes = callback.getChannel().write( buf );
// System.err.println("fin de Writable");
}
}

}
}


public void writeMessage( SocketChannel channel, String message) throws IOException {
ByteBuffer buf = ByteBuffer.wrap( message.getBytes() );
int nbytes = channel.write( buf );
System.err.println( "Wrote " + nbytes + " to channel." );
}



static final int BUFSIZE = 8;

public String decode( ByteBuffer byteBuffer ) throws CharacterCodingException {
Charset charset = Charset.forName( "us-ascii" );
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = decoder.decode( byteBuffer );
String result = charBuffer.toString();
return result;
}

public void readMessage( ChannelCallback callback) throws IOException, InterruptedException {
ByteBuffer byteBuffer = ByteBuffer.allocate( BUFSIZE );
int nbytes = callback.getChannel().read( byteBuffer );
byteBuffer.flip();
String result = this.decode( byteBuffer );
System.err.println(result);
if ( result.indexOf( "exit" ) >= 0 ) callback.getChannel().close();
else if ( result.indexOf( "shutdown" ) >= 0 ) {
callback.getChannel().close();
throw new InterruptedException();
}
else {
callback.append( result.toString() );
//If we are done with the line then we execute the callback.
if ( result.indexOf( " " ) >= 0 )
callback.execute();
}
}

public class ChannelCallback {
private SocketChannel channel;
private StringBuffer buffer;

public ChannelCallback( SocketChannel channel ) {
this.channel = channel;
this.buffer = new StringBuffer();
}

public void execute() throws IOException {
System.err.println("Execute");
System.err.println(this.buffer.toString() );
writeMessage( this.channel, this.buffer.toString() );
buffer = new StringBuffer();
}

public SocketChannel getChannel() {
return this.channel;
}

public void append( String values ) {
buffer.append( values );
}

}



public static void main( String[] args ) {

PServer nbServer = new PServer();

try {
nbServer.initialize();
} catch ( IOException e ) {
e.printStackTrace();
System.exit( -1 );
}

try {
nbServer.acceptConnections();
}

catch ( IOException e ) {
e.printStackTrace();
}

catch ( InterruptedException e ) {
}

}

}
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

RE:Selector sockets

Publicado por Tom (1831 intervenciones) el 11/02/2009 19:44:18
En tu hashMap, guárdate el objeto obtenido tras el accept() (o sea, channel, en vez de ch).
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Selector sockets

Publicado por Tom (1831 intervenciones) el 11/02/2009 19:49:59
En tu hashMap, guárdate el objeto obtenido tras el accept() (o sea, channel, en vez de ch).

Y, muy importante, acuérdate de comentar la línea:

//System.err.println(iterator.next());

ya que estás haciendo dos veces seguidas iterator->next();
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Selector sockets

Publicado por Rocio (13 intervenciones) el 11/02/2009 20:11:58
Muchas gracias,
ya lo he solucionado, he hecho algo parecido.
Me he guardado las instancias de la clase CallbackChannel :
new ChannelCallback( channel );

en la tabla, de forma en la clase almaceno el pueto local:
this.LocalPort=channel.socket().getLocalPort();

recorro todas las instancias, y en las que no coincide el puerto, escribo el mensaje:

Iterator iterator = hashMap.keySet().iterator();

ChannelCallback instanciaActual=(ChannelCallback) key.attachment();
System.err.println("canal actual: "+ instanciaActual.channel);

while( iterator.hasNext()) {
ChannelCallback x = (ChannelCallback)iterator.next();
System.err.println("canal: "+ x.channel);
if (x.getLocalPort()==instanciaActual.getLocalPort()){
System.err.println("puertos iguales");
}
else{
System.err.println("puertos diferentes");
this.writeMessage(x.channel,res);
}
}

Creo que esta solución también es buena, si no es así, ya me dirás :) gracias

Ahora estoy diseñando clientes que puedan leer y escribir, y no sólo que unos lean y otros escriban.
La verdad es que no sé cómo hacerlo, tiene que ser una especie de servidor que sólo lea y escriba? Cómo puedo hacer el método isWritable? porque he leido que los sockets se vuelven "writable" una vez que completan una peticion de lectura, y dicen que entonces no necesitamos comprobar ese caso, pero entonces cómo mando un mensaje? porque en el ejemplo que he hecho únicamente mando cuando leo algo...

Espero que me haya explicado, si alguien sabe algo, se lo agradecería :)
Gracias
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar