2009-01-22 22 views
2

Je construis une simple application client/serveur en utilisant java sockets et expérimenter avec le ObjectOutputStream etc.Java Socket Programmation

J'ai suivi le tutoriel à cette adresse http://java.sun.com/developer/technicalArticles/ALT/sockets départ à mi-chemin vers le bas quand il parle de transporter des objets sur prises

Voir mon code pour le client http://pastebin.com/m37e4c577 Cependant, cela ne semble pas fonctionner et je ne peux pas comprendre ce qui ne fonctionne pas. Le code commenté en bas est directement copié hors du tutoriel - et cela fonctionne quand je l'utilise juste au lieu de créer l'objet client.

Quelqu'un peut-il voir quelque chose que je fais mal?

+0

Vous devez le décommenter. Hah sérieusement, quelle est l'erreur de compilation? –

+0

Il n'y a pas d'erreur - cela ne fonctionne pas avec mon code non commenté et je ne vois pas pourquoi? Le code commenté fonctionne - je l'ai juste séparé et mis dans un objet réel ... ça me rend fou. – Malachi

Répondre

7

Le problème est l'ordre que vous créez les flux:

dans le serveur de l'article (que je suppose est ce que vous utilisez), lorsqu'une nouvelle connexion est ouverte, le serveur ouvre d'abord un flux d'entrée, puis un flux de sortie:

public Connect(Socket clientSocket) { 
client = clientSocket; 
try { 
    ois = new ObjectInputStream(client.getInputStream()); 
    oos = new ObjectOutputStream(client.getOutputStream()); 
} catch(Exception e1) { 
    // ... 
} 
this.start(); 
} 

Le code exemple commenté utilise l'ordre inverse, tout d'abord établir le flux de sortie, le flux d'entrée:

// 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()); 

Mais votre code, il fait l'inverse:

server = new Socket(host, port); 
in = new ObjectInputStream(server.getInputStream()); 
out = new ObjectOutputStream(server.getOutputStream()); 

L'établissement d'un flux de sortie/la paire de flux d'entrée stagnera jusqu'à ce qu'ils aient échangé leurs informations d'établissement de liaison, de sorte que vous devez correspondre à l'ordre de création. Vous pouvez le faire en inversant les lignes 34 et 35 dans votre exemple de code.

5

Vous n'écrivez l'objet nulle part.

Voir ce lien nouveau, quelque part vous devez écrire:

oos.writeObject(new Date()); 

Dans votre code, vous n'avez

ois.readObject(); 

C'est pourquoi

+0

Le code publié inclut uniquement le client, il n'a donc pas besoin d'écrire un objet. –

1

vous aimerez probablement apprendre plus basique en premier.

Voici un exemple que je viens de coder.

Il démarre un serveur , qui n'atteint qu'un seul client, et il envoie un objet et meurent. Lorsque l'utilisateur (vous) appuie sur Entrée, un nouveau client est créé, il se connecte au serveur précédemment créé et lit l'objet que le serveur enverra.

Aucune exception n'est gérée ici. Juste pour rendre les choses plus simples, mais ce n'est pas la façon dont l'exception devrait être gérée. Si vous comprenez tous les concepts ici, il sera plus facile de comprendre ceux du tutoriel.

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(); 

    } 
} 

J'espère que cela aide.

1

Si vous avez essayé un débogueur, il vous aurait dit où était le problème. (Peut-être pas pourquoi)

La question que vous avez est que ObjectOutputStream écrit un en-tête et ObjectInputStream lit cet en-tête. Vous avez d'abord créé ObjectInputStream, ce qui signifie qu'il essaie de lire un en-tête qui ne sera jamais écrit. Solution: Toujours créer l'objet ObjectOutputStream en premier et flush() avant de créer l'objet ObjectInputStream.

2

Juste un rappel. Lorsque vous utilisez ObjectOutputStream, gardez à l'esprit qu'il conserve un cache de référence. Si vous écrivez un objet, modifiez le contenu de l'objet, puis renvoyez le même objet, vous obtiendrez des données en double.Par exemple:

List list = new ArrayList(); 
list.add("value1"); 
out.writeObject(list); 
list.clear(); 
list.add("value2"); 
out.writeObject(list); 

Produira du côté client deux listes avec la chaîne "valeur1".

Pour éviter cela, la méthode de réinitialisation doit être invoqué pour réinitialiser le cache de flux lors de l'écriture la même référence d'objet à plusieurs reprises:

List list = new ArrayList(); 
list.add("value1"); 
out.writeObject(list); 
out.reset(); 
list.clear(); 
list.add("value2"); 
out.writeObject(list); 
+0

Cheers - ce sera un rappel utile! – Malachi

1

Il est préférable d'ouvrir un outputStream car un flux de sortie ne bloque pas. Ensuite, vous avez le flux d'entrée qui attend un Stream. Après tous les flux, vous écrivez dans le flux et le videz - outputStream.flush() pour envoyer les octets de données. Vous aurez également besoin d'une méthode à l'autre extrémité pour lire l'entrée, que ce soit simplement inputStream.read() qui lit chaque octet comme un entier pour un char, ou en utilisant un BufferedReader ou un Scanner. J'ai utilisé presque toutes les méthodes possibles, mais la méthode la plus efficace pour l'envoi est outputStream.write(String) qui écrit une séquence de char s comme byte s dans le flux et la lecture inputStream.read() lit un seul char. J'espère que ça aide.