Ahora observemos un segundo ejemplo. En este ejemplo, dos números son sumados. El ejemplo incluye un cliente y un servidor. Cuando el cliente tiene dos números para sumar, envía los números al servidor. El servidor entonces efectúa la adición y retorna la suma. Este ejemplo está basado en la API SocketChannel API. Otras posibles soluciones podrían emplear Web Services, RMI o Servlets.
En este ejemplo, los contenidos del ByteBuffer son dos enteros. Esto nos permite restringir el ByteBuffer a ocho bytes. También permite que podamos crear un IntBuffer que sirve como vista hacia el ByteBuffer , como sigue:
private ByteBuffer buffer = ByteBuffer.allocate(8); private IntBuffer intBuffer = buffer.asIntBuffer();El siguiente programa, SumClient , provee la parte cliente del ejemplo. Para poder ejecutar SumClient , debemos primero inicializar la parte servidor del ejemplo, SumServer , que se puede encontrar más abajo en este mismo artículo.
import java.nio.channels.SocketChannel; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.io.IOException; import java.net.InetSocketAddress; public class SumClient { private SocketChannel channel; private ByteBuffer buffer = ByteBuffer.allocate(8); private IntBuffer intBuffer = buffer.asIntBuffer(); public void getSum(int i, int j) { try { channel = connect(); sendSumRequest(i, j); receiveResponse(); } catch (IOException e) { // add exception handling code here e.printStackTrace(); } finally { if (channel != null) { try { channel.close(); } catch (IOException e) { // add exception handling code here e.printStackTrace(); } } } } private SocketChannel connect() throws IOException { InetSocketAddress socketAddress = new InetSocketAddress("localhost", 9099); return SocketChannel.open(socketAddress); } private void sendSumRequest(int i, int j) throws IOException { buffer.clear(); intBuffer.put(0, i); intBuffer.put(1, j); channel.write(buffer); System.out.println("Sent request for sum of " + i + " and " + j + "..."); } private void receiveResponse() throws IOException { buffer.clear(); channel.read(buffer); System.out.println( "Received response that sum is " + intBuffer.get(0) + "."); } public static void main(String[] args) { new SumClient().getSum(14, 23); } }El método getSum() en SumClient conecta un SocketChannel a una dirección predeterminada. El método connect() es esencialmente el mismo que el visto en el ejemplo TechTipReader , citado anteriormente. Luego de llamar a connect() , el método getSum() pasa dos enteros (en el ejemplo, 14 y 23) al método sendSumRequest() , que, en retribución, carga el ByteBuffer y escribe el contenido del SocketChannel . El método receiveResponse() entonces toma los contenidos del método y los escribe a salida estándar.
Cuando ejecutamos SumClient (luego de haber inicializado SumServer ), debería desplegar lo siguiente:
Sent request for sum of 14 and 23... Received response that sum is 37.Observando más profundamente SumClient , debe notarse que sendSumRequest() utiliza dos vistas diferentes del mismo ByteBuffer . Primero, buffer.clear() ignora la marca en el buffer, posiciona el mismo en el inicio, y setea el límite como su capacidad. En efecto limpia al buffer. Luego, el ByteBuffer es visto como un buffer que contiene dos enteros usando la manija (handle) intBuffer . El entero enviado como primer parámetro sendSumRequest() se inserta en el primer slot usando intBuffer.put(0,i) , y el segundo parámetro es similarmente posicionado en el segundo slot. El método write() de SocketChannel recibe un ByteBuffer , entonces la primera vista del buffer es requerida.
El método receiveResponse() es casi un espejo de sendSumRequest() . El buffer es limpiado nuevamente. Entonces los contenidos de SocketChannel son leídos hacia la vista ByteBuffer del buffer. Luego, el IntBuffer es utilizado para retornar el entero ubicado en la primera posición.
Antes de observar el SumServer , la parte servidor de la solución, quizá sería útil insertar una verificación en aquellos lugares en donde llamamos a los métodos read() y write() en el objeto SocketChannel . Estos métodos retornan un long con el número de bytes leídos o escritos. En este caso, nosotros esperamos ocho bytes. Ubiquemos la siguiente línea dentro del método sendSumRequest() :
channel.write(buffer);Reemplazémosla con la siguiente verificación sobre el tamaño del buffer que se está escribiendo.
if (channel.write(buffer)!= 8){ throw new IOException("Expected 8 bytes."); }Insertemos una verificación similar alrededor de la llamada channel.read() en el método receiveResponse() .
Aquí está el SumServer . Para que el ejemplo pueda ejecutarse, debemos inicializar un servidor que escuche pedidos de entrada en una ubicación determinada. En el método openChannel() citado a continuación, utilizamos el puerto 9099. Se efectúa una llamada al método estático open() de ServerSocketChannel , la siguiente línea liga (binds) el socket sobre el puerto especificado. Siempre que channel.isOpen() retorne true , un mensaje de confirmación se envía a la salida estándar.
import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.io.IOException; import java.net.InetSocketAddress; public class SumServer { ByteBuffer buffer = ByteBuffer.allocate(8); IntBuffer intBuffer = buffer.asIntBuffer(); ServerSocketChannel channel = null; SocketChannel sc = null; public void start() { try { openChannel(); waitForConnection(); } catch (IOException e) { e.printStackTrace(); } } private void openChannel() throws IOException { channel = ServerSocketChannel.open(); channel.socket().bind( new InetSocketAddress(9099)); while (!channel.isOpen()) { } System.out.println("Channel is open..."); } private void waitForConnection() throws IOException { while (true) { sc = channel.accept(); if (sc != null) { System.out.println( "A connection is added..."); processRequest(); sc.close(); } } } private void processRequest() throws IOException { buffer.clear(); sc.read(buffer); int i = intBuffer.get(0); int j = intBuffer.get(1); buffer.flip(); System.out.println("Received request to add " + i + " and " + j); buffer.clear(); intBuffer.put(0, i + j); sc.write(buffer); System.out.println("Returned sum of " + intBuffer.get(0) + "."); } public static void main(String[] args) { new SumServer().start(); } }Cuando ejecutamos SumServer , debería desplegar lo siguiente:
Channel is open... Sent request for sum of 14 and 23... Received response that sum is 37.Luego, cuando ejecutamos SumClient , SumServer debería mostrar lo siguiente:
A connection is added... Received request to add 14 and 23 Returned sum of 37.En el método waitForConnection() , la aplicación entra en un ciclo hasta que se recibe un pedido de conexión hacia el ServerSocketChannel . Cuando un pedido llega, channel.accept() retorna un SocketChannel , por lo que la variable sc ya no es más null . La petición entrante es procesada, y luego el SocketChannel se cierra. El servidor espera entonces por otra petición de conexión. Nótese que en este sencillo ejemplo las peticiones son procesadas enteramente una por vez Una estructura diferente se requeriría para un servidor que debe manejar múltiples peticiones concurrentes.
El método processRequest() es muy similar a los métodos correspondientes en SumClient . El buffer se limpia, el canal se lee hacia el buffer. Luego, la vista IntBuffer se utiliza para obtener los dos enteros contenidos en el buffer. El buffer luego se limpia y la suma se inserta en el mismo usando la vista IntBuffer . El buffer luego se escribe hacia el cliente utilizando SocketChannel .
Usuarios que han visto este tema también han visto...
- Crear tu Primer Applet
- Transformar XML en HTML utilizando XSL y API Java
- La clase ArrayList en Java
- Incorporando RSS Feeds a Web Apps basados en JSP utilizando JSP Tags
- Centrar una ventana en la pantalla
Información legal | Política de Privacidad | Contacte con nosotros
Otro proyecto de Factoría de Internet. Copyright© 2003-2011 Factoría de Internet S.L.. Todos los derechos reservados.