upload lent

JijoJijo Membre
07:53 modifié dans API AppKit #1
Bonjour,

J'ai une fonction qui envoie une image encodée en base 64 par le biais d'une requête xml-rpc.
Cela fonctionne trés bien, le seul problème c'est que cela est lent.

Voici ci-dessous ma fonction:

- (void)upload:(NSString*)session Epath:(NSString*)path Efilename:(NSString*)filename {


NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

// URL du serveur
NSURL * url=[NSURL URLWithString:@"http://url-server"];

// methode appelée
NSString * methode=@methode;

        // création du webservice
WSMethodInvocationRef webservice = WSMethodInvocationCreate ((CFURLRef) url, (CFStringRef) methode, kWSXMLRPCProtocol);

// création du dictionnaire contenant la structure
NSMutableDictionary * member =[[NSMutableDictionary alloc] init];

NSData * myData = [NSData dataWithContentsOfFile:path];

// remplissage de ce dictionnaire
[member setObject:@12345a12345b12345c12345d forKey:@key];
[member setObject:session forKey:@session];
[member setObject:myData forKey:@data];
[member setObject:filename forKey:@filename];

// création du dictionnaire contenant les paramètres du web service
NSDictionary * params=[NSDictionary  dictionaryWithObject:member forKey:@inutile];
[member release];

        // mise en place des paramètres dans l'appel au web service
WSMethodInvocationSetParameters(webservice, (CFDictionaryRef)params, NULL);

        // utilisation du flag de debug pour observer le xml généré
//WSMethodInvocationSetProperty(webservice, kWSDebugOutgoingBody, kCFBooleanTrue);

        // exécution du web service
NSDictionary * resultat =(NSDictionary *)WSMethodInvocationInvoke(webservice);

[pool release];

}

Request format

<?xml version="1.0"  encoding="UTF-8"?>
<methodCall>
<methodName>methode</methodName>
<params>
<param>
<value><struct>
<member><name>key</name>
<value><string>12345a12345b12345c12345d</string></value>
</member>
<member><name>session</name>
<value><string>0f16a26a812a1621b673211123501af9</string></value>
</member>
<member><name>data</name>
<value><base64>binary data</base64></value>
</member>
<member><name>filename</name>
<value><string>filename.jpg</string></value>
</member> 
</struct></value>
</param>
</params>
</methodCall>


Je ne sais pas si on peut accélérer la fonction ou si on peut effectuer des threads pour envoyé plusieurs photos en même temps.


Merci

Réponses

  • MalaMala Membre, Modérateur
    07:53 modifié #2
    Question bête mais ton problème de lenteur ne viendrais pas simplement de ta bande passante en upload? Tu testes sur un serveur distant ou bien sur un réseau local?
  • JijoJijo Membre
    07:53 modifié #3
    Non ce n'est pas la bande passante qui pose un problème. Sinon je teste sur un serveur distant.

    C'est bien ma fonction qui est longue à  encoder un fichier en base 64 et à  l'envoyer.
  • dilarogadilaroga Membre
    07:53 modifié #4
    J'avais lu un article interessant qui proposait une solution pour l'encodage/decodage en base64, peut être il t'aidera à  optimiser ta méthode :

    Base64 encoding in Cocoa

  • schlumschlum Membre
    07:53 modifié #5
    xml-rpc n'est pas capable de travailler sans encoder en base-64 ?
    Je bosse beaucoup avec gsoap, je peux te dire que si je m'amusais à  encoder / décoder tous les blobs en base-64 ça serait la mort  :o
  • JijoJijo Membre
    janvier 2009 modifié #6
    L'encodage en base 64 est inévitable car je dois respecter les critéres et methodes de l'API du serveur distant.

    Je ne connais pas trop les threads mais cela peut il résoudre mon probléme pour la vitesse, en envoyant des photos en simultanées par exemple?


    Car comparé à  d'autre plugin d'iPhoto je suis lent.

    Merci
  • schlumschlum Membre
    07:53 modifié #7
    dans 1231352019:

    L'encodage en base 64 est inévitable car je dois respecter les critéres et methodes de l'API du serveur distant.

    Je ne connais pas trop les threads mais cela peut il résoudre mon probléme pour la vitesse, en envoyant des photos en simultanées par exemple?


    Car comparé à  d'autre plugin d'iPhoto je suis lent.

    Merci


    Tu peux pré-traiter plusieurs images à  la fois en les convertissant via des threads... mais en envoyer plusieurs à  la fois ça risque d'être plus le bazar qu'autre chose !
  • JijoJijo Membre
    07:53 modifié #8
    Oui tu as a raison. Le hic c'est que ma fonction n'encode mon image que lors de l'envoie de la requête.
    Du coup avec cette fonction je ne peux pas utiliser ton raisonnement  :'( .

    J'ai posté un exemple de ma fonction pour le montrer.

    Collez mon code dans le main.m d'une appli cocoa.

    Ensuite il  suffit de remplacer à  la ligne NSString *path = @/Users/nomUSER/Desktop/test.png"; nomUSER par votre nom de session et de créer une image du nom test.png sur votre bureau. Créez en une petite de préférence.



    Je ne sais pas si je peux retravailler ma fonction ou si je dois tout recommencer afin d'encoder et ensuite envoyé la requête.



    PS: Ne vous inquiétez pas pour la méthode et l'url du serveur qui n'ont rien à  voir avec ce que je fais. C'est juste que pour générer une requête xml-rpc il faut une url valide.
    // URL du serveur
    NSURL * url=[NSURL URLWithString:@"http://betty.userland.com/RPC2"];

    // methode appelée
    NSString * methode=@maMethode;


  • schlumschlum Membre
    07:53 modifié #9
    Pourquoi n'as tu pas les moyens de pré-encoder les images au moment où tu les charges ??
  • JijoJijo Membre
    janvier 2009 modifié #10
    Je ne sais pas faire autrement. Je n'arrive pas a encoder une image en base 64 d'une autre manière. Je ne trouve et ne comprend pas bien les exemples pour encoder un fichier.

    Ma fonction elle encode qu'a l'envoie de la requête.




  • AliGatorAliGator Membre, Modérateur
    07:53 modifié #12
    La méthode dans le lien de dilaroga ne te convient pas ?
  • JijoJijo Membre
    07:53 modifié #13
    A vrai dire j'essaie en vain d'utiliser  l'exemple de [size=10pt]dilaroga[/size]. Cependant j'ai vraiment du mal a comprendre l'exemple (projet xcode).

    Je n'arrive pas à  refaire pour mon cas.

    :crackboom:-
  • AliGatorAliGator Membre, Modérateur
    07:53 modifié #14
    Télécharges le projet Xcode fourni dans le lien, et tu as juste à  inclure "NSData-Base64Extensions.h" et "NSData-Base64Extensions.m" dans ton propre projet (et sans doute à  ajouter le framework OpenSSL à  ton projet, quand même) pour que ça marche.
    Il utilise des catégories, ce qui permet de rajouter en l'occurence les méthodes [tt]encodeBase64[/tt] et [tt]encodeBase64WithNewlines:[/tt] directement dans la classe NSData de Cocoa.

    Du coup quand tu as un [tt]NSData* d[/tt] que tu veux encoder en Base64 (dans ton cas le NSData représentant ton image), il suffit de faire [tt]NSString* base64encoded = [d encodeBase64];[/tt] pour récupérer la chaà®ne base64 correspondant à  tes NSData.
  • schlumschlum Membre
    07:53 modifié #15
    Boah, vous n'êtes pas drôles... C'est plus rigolo de l'écrire soi-même ; c'est comme ça qu'on se forme  :)
  • JijoJijo Membre
    07:53 modifié #16
    Je ne sais pas pourquoi j'ai des erreurs à  la compilation.
    Pourtant j'ai mis les includes comme tu m'a dis pour openssl
    #include <openssl/bio.h>
    #include <openssl/evp.h>

    voici les erreurs


  • ChachaChacha Membre
    07:53 modifié #17
    dans 1231439177:

    Je ne sais pas pourquoi j'ai des erreurs à  la compilation.

    Ce ne sont pas des erreurs de compilation mais de "linking". Autrement dit, le code est correct, et est déjà  compilé, mais les différents morceaux de codes compilés ne peuvent être liés les uns aux autres car il en manque des bouts.
    Exemple : grâce à  tes headers, tu dis au *compilateur* "je vais utiliser telles fonctions, dont les prototypes sont les suivants". Le compilateur te croit sur parole, et génère du code prêt à  appeler ces fonctions (il sait comment gérer la pile pour les différents types de paramètres prévus pour ces fonctions, même s'il ne sait pas encore où trouver les fonctions en question).
    Mais au moment de finaliser l'exécutable, il doit réaliser les liens, c'est-à -dire qu'à  chaque appel de fonction, il doit aller chercher la véritable addresse de la fonction, dans le bon module, et insérer cette addresse à  l'endroit prévu.

    Dans ton exemple, il te manque un lien vers une bibliothèque de OpenSSL.
    S'il existait un "framework OpenSSL" sous MacOS, il suffirait de glisser ce framework dans les dépendances de ton projets, et ce serait fait automatiquement. Mais bon, OpenSSL est distribué sous forme de bibliothèques dans /usr/lib.
    Dans ton exemple, il te manque libcrypto.dylib
    Pour la rajouter, spécifie -lcrypto dans les "Other Linker flags" de ta target.

    Au passage,  libcrypto étant standard sous MacOS (elle "fait partie" de l'OS), tu peux linker tranquillement avec la libcrypto de base, qu'il trouvera tout seul dans /usr/lib, et que tu n'as pas besoin d'embarquer dans ton appli. Ce serait différent pour une bibliothèque non standard.

    J'ai été disert, mais ça fait pas de mal :-)

    +
    Chacha

  • JijoJijo Membre
    07:53 modifié #18
    Merci beaucoup pour cette réponse rapide , efficace et très informative.
    Cela marche nikel.
  • JijoJijo Membre
    07:53 modifié #19
    Je pensais contourner mon problème d'encodage en base 64 lors de la génération et l'envoie de la requête en encodant mon fichier avant.

    Cependant je me suis rendu compte que toute valeur de type NSData est encodée en base 64 lors de la génération et l'envoie de la requête.

    Du coup inévitablement mon image de type NSData est encodée lors de l'envoie.

    Ensuite j'ai essayé un framework XMLRPC open source. Mais là  aussi c'est la même chose.

    Ne pouvant donc par remédier à  ce problème je voudrai savoir si quelqu'un savais obtenir le nombre d'octet envoyé pour donner un sentiment de vitesse à  l'utilisateur.


    exemple pour le plugin flikR



  • schlumschlum Membre
    07:53 modifié #20
    Si tu le transformes en NSString ?
  • JijoJijo Membre
    07:53 modifié #21
    Oui c'est une possibilité qui marche mais la requête doit avoir l'encodage en base 64 entre des balises <base64> et non <string>.


  • schlumschlum Membre
    07:53 modifié #22
    Et y a pas une méthode pour que ça puisse être envoyé en "base64" ?
    Si non, ça manque...
  • JijoJijo Membre
    07:53 modifié #23
    Si il suffit de passer une variable de type NSdata, de ce fait celle-ci est contenu entre des balises <base64> et est encodée en base 64 à  l'envoie de la requête.

  • schlumschlum Membre
    07:53 modifié #24
    Je voulais parler de base64 brut... pas passé à  la moulinette...
  • JijoJijo Membre
    janvier 2009 modifié #25
    Je ne vois pas trop ce que tu veux dire.
  • schlumschlum Membre
    07:53 modifié #26
    Ben simplement pouvoir lui donner quelque chose qui a été pré-encodé quoi...
  • JijoJijo Membre
    janvier 2009 modifié #27
    Je ne sais pas. J'ai essayé comme je l'ai dit d'encoder avant avec le framework openssl.

    NSString *path = @/Users/nomUser/Desktop/image.png;

    // récupération du fichier
    NSData * data = [NSData dataWithContentsOfFile:path];

    // encodage en base 64
    NSString * base64encoded =[data encodeBase64];

    // conversion de NSString en NSData
    const char * utfString = [base64encoded UTF8String];
    NSData * Data = [NSData dataWithBytes: utfString length: strlen(utfString)];


    Mais cela est inutile car Data sera réencodé à  l'envoie. Au final le fichier envoyé sera encodé 2 fois en base 64.
  • AliGatorAliGator Membre, Modérateur
    07:53 modifié #28
    Je pense que schlum te proposait d'envoyer directement "base64encoded", à  savoir ta variable de type NSString et non pas de la ré-encapsuler dans une variable de type NSData... Mais comme tu l'as dit plus haut, si tu fais ça (envoyer la NSString* base64encoded au lieu de la NSData* data), ça va l'encadrer dans une balise de type <string>...</string> et non plus <base64>...</base64>, donc ton API XMLRPC de l'autre côté ne va pas aimer sans doute... :-/
  • schlumschlum Membre
    07:53 modifié #29
    Ce que je disais, c'est qu'il faudrait peut-être ajouter un argument à  l'API pour les NSString (ou les NSData, au choix...) pour dire si c'est du base64 ou non.
  • JijoJijo Membre
    07:53 modifié #30
    Finalement j'ai pu trouver une autre alternative à  l'upload en utilisant une méthode post en php.

    L'upload est désormais rapide.

    Cela dit j'aimerai bien compter les octets envoyés ou avoir un pourcentage sur la progression de l'upload. Par contre je n'ai aucune idée pour le faire.


  • AliGatorAliGator Membre, Modérateur
    07:53 modifié #31
    Je sais que l'upload en POST via PHP ne permet pas d'avoir un pourcentage d'avancement malheureusement, il me semble que j'avais cherché à  une époque justement. Par contre il existe des scripts (en perl je crois) qui permettent de le faire... Tu devrais trouver ça sur le net, l'idée est d'installer sur le serveur un petit script qui te donne la taille d'un fichier donné, et du coup tu demandes régulièrement la taille de ton fichier en cours d'upload comme ça tu peux comparer avec la taille finale du fichier et en déduire ta progression.
Connectez-vous ou Inscrivez-vous pour répondre.