2017-06-08 4 views
0

J'essaie d'envoyer un fichier via des sockets Java d'un programme à l'autre. Mon code est basé sur this question. Le problème est que sur la machine Ubuntu hébergeant le serveur, le fichier envoyé a une taille de 0 octet. Le code a travaillé sur une connexion locale sur mon ordinateur portable Windows, donc peut-être le problème a à voir avec la connexion à distance?FileOutputStream écrit 0 octets

Code Serveur:

int g = Integer.parseInt(in.readLine()); 
if(g > -1) { 
    InputStream fIn = client.getInputStream(); 
    for(int i = 0; i < g; i++) { 
     String name = in.readLine(); 
     byte[] bytes = new byte[16*1024]; 
     File f = new File("plugins/" + name + ".jar"); 
     if(!f.exists()) f.createNewFile(); 
     FileOutputStream fOut = new FileOutputStream(f); 
     int count; 
     while ((count = fIn.read(bytes)) >= 0) { 
      fOut.write(bytes, 0, count); 
     } 
     fOut.flush(); 
     fOut.close(); 
    } 
    System.out.println("[" + client.getRemoteSocketAddress().toString() + "] added " + g + " new plugins."); 
    client.close(); 
}else{ 
    client.close(); 
} 

Code client:

JFileChooser fd = new JFileChooser("C:\\");       
fd.setFileSelectionMode(JFileChooser.FILES_ONLY); 
fd.setMultiSelectionEnabled(true); 
fd.setFileFilter(new FileNameExtensionFilter(null,"jar")); 
int r = fd.showOpenDialog(null); 
if(r == JFileChooser.APPROVE_OPTION) { 
    File[] files = fd.getSelectedFiles(); 
    OutputStream fOut = sock.getOutputStream(); 
    out.println(files.length); 
    for(File f : files) { 
     out.println(f.getName().split("\\.")[0]); 
     byte[] bytes = new byte[16 * 1024]; 
     FileInputStream fIn = new FileInputStream(f); 
     int count; 
     while ((count = fIn.read(bytes)) >= 0) { 
      fOut.write(bytes, 0, count); 
     } 
     fIn.close(); 
    } 
}else{ 
    out.println(-1); 
} 
sock.close(); 

0 bytes

+0

Quel type d'objet est 'client'? Le premier élément/ligne est le nombre de fichiers. Ajouter la partie le lit le nombre de fichiers? Il existe différents problèmes dans votre code: Il n'y a pas de délimiteur dans votre flux qui indique au serveur que tous les octets d'un fichier ont été lus et qu'un nouveau fichier commence. Votre gestion des exceptions/ressources. Vous ne pouvez pas fermer tous vos flux dans le cas d'une exception qui peut devenir un gros problème du côté serveur. – andih

+0

Le client @andih est un Socket. Pour chaque nouveau client connecté au serveur, le socket est passé à un thread, de sorte que le code "Serveur" est imbriqué dans run(). Oui, la première ligne lit le nombre de fichiers, voir les modifications. –

+0

@andih Peut-être pourriez-vous poster une réponse en ajoutant le délimiteur? En outre, je gère les exceptions en dehors du code donné. Comment mon traitement des exceptions peut-il devenir un "gros problème" du côté du serveur? Une fois le protocole terminé, les deux parties terminent la connexion. Si une erreur survient côté serveur lors de la fermeture du socket client, le thread se termine. Fondamentalement, s'il semble y avoir un problème, les deux parties se termineront. –

Répondre

0

Comme dit dans les commentaires, il y a différents problèmes dans votre code.

Pour reconnaître la fin d'un seul fichier, vous pouvez simplement ajouter la taille du fichier après le nom du fichier séparé par un point-virgule;

out.println(f.getName().split("\\.")[0] + "; size" + f.length()); 

Sur le côté serveur vous accumulez la taille du fichier de lecture/arrêt écrit lec ture le contenu du fichier fermer et lire la ligne suivante (nom de fichier/taille du fichier). Comme indiqué dans les commentaires, il existe différents problèmes. Vous utilisez fIn et fOut, ce qui n'est pas clair comment ils sont définis. Côté client, vous utilisez fOut tandis que Socket OutputStream est nommé 'out'. Une chose similaire sur le côté serveur. Vous avez lu le nombre de fichiers de in, mais après, vous obtenez le InputStream (encore?) À partir du Socket et l'utiliser comme fIn. En fonction de votre in qui peut ou ne peut pas fonctionner.

Lire également une ligne de via readLine à partir d'un InputStream et aussi le contenu binaire n'est pas si trivial. Dans mon code d'exemple, j'utilise le DataInputStream car même la méthode readLine est obsolète.

L'exemple utilise également la syntaxe "try with resources" pour s'assurer que toutes les ressources (Streams, Sockets) sont fermées dans le cas d'une exception.

L'exemple ne montre pas comment gérer la taille du fichier côté serveur C'est à vous de décider.

L'exemple est complètement exécutable sur une seule machine et montre comment copier un seul fichier via une socket en fonction de votre code.

import java.io.DataInputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.OutputStream; 
import java.io.PrintStream; 
import java.net.InetAddress; 
import java.net.InetSocketAddress; 
import java.net.ServerSocket; 
import java.net.Socket; 

public class ClientServerSocketExample { 

    private static class Server { 

     public void run() throws IOException { 

      try (ServerSocket serverSocket = new ServerSocket(41000, 10, InetAddress.getLocalHost())) { 
       try (Socket client = serverSocket.accept()) { 

        try (DataInputStream in = new DataInputStream(client.getInputStream())) { 

         int g = Integer.parseInt(in.readLine()); 

         if(g > -1) { 
          for(int i = 0; i < g; i++) { 
           String[] filenameAndSize = in.readLine().split(";"); 
           String name = filenameAndSize[0]; 
           byte[] bytes = new byte[16*1024]; 
           File f = new File("/tmp/" + name + ".jar"); 
           if(!f.exists()) f.createNewFile(); 
           try (FileOutputStream fOut = new FileOutputStream(f)) { 
            int count; 
            while ((count = in.read(bytes)) >= 0) { 
             fOut.write(bytes, 0, count); 
            } 
            fOut.flush(); 
           } 
          } 
          System.out.println("[" + client.getRemoteSocketAddress().toString() + "] added " + g + " new plugins."); 


         } 
        } 
       } 
      } 
     } 

    } 

    private static class Client { 

     public void run() throws IOException { 
      try (Socket socket = new Socket()) { 
       socket.connect(new InetSocketAddress(InetAddress.getLocalHost(), 41000)); 

       sendFiles(socket); 
      } 
     } 

     private static void sendFiles(Socket sock) throws IOException { 
      File[] files = new File[]{new File("some.jar")}; 
      OutputStream fOut = sock.getOutputStream(); 
      PrintStream out = new PrintStream(fOut); 

      out.println(files.length); 
      for(File f : files) { 
       out.println(f.getName().split("\\.")[0] + "; size" + f.length()); 

       byte[] bytes = new byte[16 * 1024]; 
       try (FileInputStream fIn = new FileInputStream(f)) { 
        int count; 
        while ((count = fIn.read(bytes)) >= 0) { 
         out.write(bytes, 0, count); 
        } 
        out.flush(); 
       } 
      } 
     } 


    } 



    public static void main(String ... args) throws IOException, InterruptedException { 
     new Thread(new Runnable() { 

      @Override 
      public void run() { 
       try { 
        new Server().run(); 
       } catch (IOException ioe) { 
        System.out.println(ioe); 
       } 


      } 

     }).start(); 

     System.out.println("Waiting for the Server to come up"); 
     Thread.sleep(500); 

     new Client().run(); 
    } 

} 

Il peut y avoir un problème dans cette solution lorsque le client envoie un \r comme nouveau séparateur de ligne et le fichier commence par \n. Le serveur peut compter le \n dans le séparateur de ligne et le fichier sera corrompu (un octet manquera).