Programación Java Socket
sockets network-programming (6)
Estoy construyendo una aplicación cliente / servidor simple usando conectores Java y experimentando con ObjectOutputStream, etc.
He estado siguiendo el tutorial en esta url http://java.sun.com/developer/technicalArticles/ALT/sockets comenzando a mitad de camino cuando se trata de transportar objetos por sockets.
Ver mi código para el cliente http://pastebin.com/m37e4c577 Sin embargo, esto no parece funcionar y no puedo entender lo que no funciona. El código comentado en la parte inferior se copia directamente del tutorial, y esto funciona cuando lo uso en lugar de crear el objeto cliente.
¿Alguien puede ver algo que estoy haciendo mal?
No estás escribiendo el objeto en ninguna parte.
Ver ese enlace de nuevo, en algún lugar que tengas que escribir:
oos.writeObject( new Date() );
En tu código solo tienes
ois.readObject();
Es por eso
El problema es el orden en que está creando las transmisiones:
En el servidor del artículo (que supongo que es lo que está usando), cuando se abre una nueva conexión, el servidor abre primero una secuencia de entrada y luego una secuencia de salida:
public Connect(Socket clientSocket) {
client = clientSocket;
try {
ois = new ObjectInputStream(client.getInputStream());
oos = new ObjectOutputStream(client.getOutputStream());
} catch(Exception e1) {
// ...
}
this.start();
}
El código de ejemplo comentado utiliza el orden inverso, primero establece la secuencia de salida y luego la secuencia de entrada:
// open a socket connection
socket = new Socket("localhost", 2000);
// open I/O streams for objects
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());
Pero tu código lo hace al revés:
server = new Socket(host, port);
in = new ObjectInputStream(server.getInputStream());
out = new ObjectOutputStream(server.getOutputStream());
El establecimiento de una secuencia de salida / par de flujo de entrada se detendrá hasta que hayan intercambiado su información de intercambio, por lo que debe coincidir con el orden de creación. Puede hacer esto simplemente cambiando las líneas 34 y 35 en su código de ejemplo.
Probablemente le gustará aprender lo más básico primero.
Aquí hay una muestra que acabo de codificar.
Inicia un servidor , que atiende solo a UN cliente, y envía un objeto y muere.
Cuando el usuario (usted) presiona enter, se crea un nuevo cliente , se conecta al servidor creado previamente y lee el objeto que el servidor enviará.
No se trata ninguna excepción aquí. Solo para simplificar las cosas, pero esta NO es la forma en que se debe manejar la excepción.
Cuando comprenda todos los conceptos aquí, será más fácil comprenderlos en el tutorial.
import java.io.*;
import java.net.*;
import java.util.*;
public class SimpleServer implements Runnable {
// Creates the server, send a "date" and die.
public void run() {
try {
ServerSocket server = new ServerSocket( 8090 );
Date creationDate = new Date();
System.out.println("(Server) Server is ready "
+ "and running at " + creationDate );
Socket uniqueClient = server.accept();
// We will write using this "chained" object.
ObjectOutputStream out = new ObjectOutputStream(
uniqueClient.getOutputStream());
out.writeObject( creationDate );
// close all, at this point forget about the exceptions.
// this is lesson #1
out.close();
uniqueClient.close();
server.close();
System.out.println("(Server) The server is down");
}catch( IOException ioe ) {}
}
public static void main ( String [] args ) throws IOException ,
ClassNotFoundException {
Thread serverThread = new Thread( new SimpleServer() );
serverThread.start(); // start the server thread ... doh..
System.out.println("(Client) Press enter when you want "+
" to connect to the server...");
Scanner scanner = new Scanner( System.in );
scanner.nextLine();
Socket client = new Socket("localhost", 8090 );
// Read from this object.
ObjectInputStream in = new ObjectInputStream( client.getInputStream() );
Date date = ( Date ) in.readObject();
System.out.println("(Client) Current time is: " + new Date() );
System.out.println("(Client) Object read from server : " + date );
in.close();
client.close();
}
}
Espero que esto ayude.
Si intentaste un depurador, te habría indicado dónde estaba el problema. (Quizás no por qué)
El problema que tiene es que ObjectOutputStream escribe un encabezado y ObjectInputStream lee ese encabezado. Primero ha creado ObjectInputStream, lo que significa que está intentando leer un encabezado que nunca se escribirá.
Solución: siempre cree ObjectOutputStream primero y descargue () antes de crear ObjectInputStream.
Simplemente un recordatorio.
Cuando use ObjectOutputStream, tenga en cuenta que mantiene un caché de referencia. Si escribe un objeto, cambia los contenidos del objeto y luego envía el mismo objeto nuevamente, obtendrá datos duplicados. Por ejemplo:
List list = new ArrayList();
list.add("value1");
out.writeObject(list);
list.clear();
list.add("value2");
out.writeObject(list);
Producirá en el lado del cliente dos listas con la cadena "value1".
Para evitar esto, se debe invocar el método de reinicio para restablecer la caché de la secuencia al escribir la misma referencia de objeto varias veces:
List list = new ArrayList();
list.add("value1");
out.writeObject(list);
out.reset();
list.clear();
list.add("value2");
out.writeObject(list);
Es mejor abrir un outputStream
porque una secuencia de salida no se bloquea. Luego, tiene la secuencia de entrada que espera una transmisión. Después de todas las transmisiones, escribe en la secuencia y la outputStream.flush()
- outputStream.flush()
para enviar los bytes de datos. También necesitará un método en el otro extremo para leer la entrada, ya sea simplemente inputStream.read()
que lee cada byte como un entero para un char
, o usando un BufferedReader
o Scanner
. He usado casi todos los métodos posibles, pero el método más efectivo para enviar es outputStream.write(String)
que escribe una secuencia de caracteres como byte
en la transmisión y leyendo inputStream.read()
lee un solo char
. Espero que esto ayude.