envoyer des fichiers volumineux sur socket java


J'essaie de transférer des fichiers plus volumineux sur socket.Je vais transférer le fichier dans chunks.As indiqué dans le code.lien

int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0)
{
  out.write(buffer, 0, count);
}

Avant d'envoyer ce fichier,je veux envoyer un objet qui détient les détails du fichier.En utilisant quel flux dois-je envoyer Objet + Fichier.

Je suis nouveau sur les flux,puis-je obtenir un exemple de code.

Puis-je d'abord envoyer la longueur d'octet de l'objet pour lire l'objet, l'enregistrer et envoyer un fichier data.is c'est possible, n'importe quel exemple de code ?

Merci 421

Author: Community, 2014-09-07

3 answers

Je ne sais pas si l'utilisation du mécanisme de sérialisation de Java est la meilleure façon de faire un simple transfert de fichiers. Comme votre question le suggère, vous essayez d'éviter de garder le fichier entier en mémoire à tout moment. Cela peut être fait avec des objets utilisant le modèle Proxy mais si tout ce que vous voulez faire est de transférer le fichier, ce n'est peut-être pas la solution la plus simple. (En outre, il liera efficacement votre pair pour être implémenté en Java aussi.)

Au lieu de cela, pourquoi ne pas jeter un oeil à un extrêmement protocole réussi qui fait exactement ce dont vous avez besoin: HTTP.

Content-Type: application/octet-stream
Content-Length: 542183

542183 bytes of data follow...

Il ne devrait pas être trop difficile pour vous d'écrire un analyseur pour l'en-tête de méta-données.

 0
Author: 5gon12eder, 2014-09-07 12:26:46

Vous devez assurer l'ordre d'écriture/lecture. Si write an object -> write raw bytes sur le client, alors read an object -> read raw bytes sur le serveur. Lors de la lecture, ObjectInputStream devrait pouvoir trouver la limite des données de l'objet sérialisé.

Si vous voulez garder une connexion socket longue durée et utiliser ses flux plusieurs fois, envelopper Output/InputStream socket dans un ObjectOutput/InputStream n'est pas une bonne idée IMO. Lorsque vous fermez un flux d'objet, il ferme également le flux sous-jacent.

Vous pouvez donc écrire la longueur des données d'objet sérialisées en premier (la longueur du fichier est contenue dans l'objet, vous n'avez donc pas besoin de l'écrire explicitement), par exemple 4 octets de BigEndian codé int. Ensuite, sérialisez l'objet dans un ByteArrayOutputStream et écrivez les octets dans son tampon. Sur le serveur, lisez d'abord 4 octets, décodez les octets en int et lisez ce nombre d'octets dans un byte[], enveloppez le tableau d'octets avec un ByteArrayInputStream et désérialisez l'objet à partir de celui-ci.

Écrivez comme ceci:

......
OutputStream out = socket.getOutputStream();

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);  

oos.writeObject(fileInfoObject);
oos.close();

byte[] header = encodeInteger(baos.size());

out.write(header, 0, 4);
baos.writeTo(out);

// write the file to out just as your question shows

Du côté récepteur: ...... InputStream in = socket.getInputStream ();

// read the int
byte[] header = new byte[4];

in.read(header, 0, 4);

int size = decodeInteger(header);

// read the object
byte[] objectbuf = new byte[size];

int count;

while((count += in.read(objectbuf)) < size); // not sure if this works...

ObjectInputStram ois = new ObjectInputStream(new ByteArrayInputStream(objectbuf));

Object fileInfoObject = ois.readObject();
ois.close();

// read the file
FileOutputStream fos = new FileOutputStream(new File("somefile"));

byte[] buffer = new byte[8192];
count = 0;
long left = castedFileInfoObject.fileSize;

// also not sure if this works, not tested.
int maxRead = buffer.length;

while (true) {
    count = in.read(buffer, 0, maxRead);

    left -= count;

    if (left < 8192) {
        maxRead = (int)left;
    }

    fos.write(buffer, 0, count);

    if (left == 0) {
        break;
    }
}

Je n'ai pas testé l'exemple de code dans ma réponse.. juste pour montrer l'idée.

 0
Author: coolcfan, 2014-09-07 13:11:59

La classe MyClass doit implémenter l'interface sérialisable. Ensuite, un objet de cette classe peut être écrit dans un ObjectOutputStream et lu à partir d'ObjectInputStream en utilisant les méthodes writeObject et readObject (Voir ci-dessous).

Sur le Client:

Socket socket = new Socket(url, port);  
OutputStream os = socket.getOutputStream();  
ObjectOutputStream oos = new ObjectOutputStream(os);  
MyClass obj = new Myclass();  
oos.writeObject(obj);  
int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0) {
  out.write(buffer, 0, count);
}

Sur le serveur:

ServerSocket sSocket = new ServerSocket(port);
Socket socket = sSocket.accept();  
InputStream is = socket.getInputStream();  
ObjectInputStream ois = new ObjectInputStream(is);  
MyClass obj = (MyClass)ois.readObject();
byte arr[];
try {
  while(arr = (byte[])ois.readObject()) {
    //do something with arr
  }
} catch(java.io.EOFException) {
  // End of data
}

Si vous devez envoyer plus de données après la fin du fichier, vous avez besoin d'un moyen de déterminer le nombre d'octets du fichier. Ensuite, vous pouvez envoyer le nombre d'octets au préalable sur le socket au serveur. Sur le serveur, lisez uniquement ce nombre d'octets d'informations pour le fichier, puis faites de même pour le reste des données que vous allez envoyer. Cette stratégie de pré-envoi de la taille du fichier est recommandée et est principalement utilisée lors de tout transfert de données. Si vous pouvez le faire, vous n'avez pas à compter sur la capture java.io.EOFException pour détecter la fin des données.

 -1
Author: Ashu Pachauri, 2014-09-07 12:19:45