NSStream Fermeture

Bonjour tout le monde,



J'ai un petit problème avec NSInputStream/NSOutputStream.



J'explique un peu...

Pour vous épargner de lire un peu près deux fois la même chose, sachez qu'en réalité tout est doublé: j'ai 2 NSInputStream et 2 NSOutputStream, oui, deux ports différents.



J'ai dans ma classe :

[/size][/font][/color][color=#008C00][font=Menlo][size=2]<br />
[color=#7c1fae]NSInputStream[/color][color=#000000] *inputStream; [/color]//Flux input (à  envoyer)[/size][/font][/color][color=#008C00][font=Menlo][size=2]<br />
[color=#7c1fae]NSOutputStream[/color][color=#000000] *outputStream; [/color]//Flux output (à  recevoir)[/size][/font][/color]<br />










J'initialise ma connexion ainsi :


[font=Menlo][size=2]<br />
-([color=#cd00a5]void[/color])initNetWorkCommunication[/size][/font][font=Menlo][size=2]<br />
{ [/size][/font][color=#E40000][font=Menlo][size=2]<br />
[color=#460085]NSLog[/color][color=#000000]([/color]@&quot;Entree dans initNetWorkCommunication&quot;[color=#000000]);[/color][/size][/font][/color]<br />
[color=#008C00][font=Menlo][size=2]<br />
//Streams Commandes[/size][/font][/color][color=#7C1FAE][font=Menlo][size=2]<br />
CFReadStreamRef[color=#000000] readStream;[/color][/size][/font][/color][color=#7C1FAE][font=Menlo][size=2]<br />
CFWriteStreamRef[color=#000000] writeStream;[/color][/size][/font][/color][font=Menlo][size=2]<br />
[color=#460085]CFStreamCreatePairWithSocketToHost[/color]([color=#cd00a5]NULL[/color], ([color=#7c1fae]CFStringRef[/color])[color=#e40000]@&quot;192.168.11.123&quot;[/color], [color=#3800df]2000[/color], &amp;readStream, &amp;writeStream);[/size][/font]<br />
[color=#7C1FAE][font=Menlo][size=2]<br />
[color=#460085]CFReadStreamSetProperty[/color][color=#000000](readStream, [/color]kCFStreamPropertyShouldCloseNativeSocket[color=#000000], [/color]kCFBooleanTrue[color=#000000]);[/color][/size][/font][/color][color=#7C1FAE][font=Menlo][size=2]<br />
[color=#000000]    [/color][color=#460085]CFWriteStreamSetProperty[/color][color=#000000](writeStream, [/color]kCFStreamPropertyShouldCloseNativeSocket[color=#000000], [/color]kCFBooleanTrue[color=#000000]);[/color][/size][/font][/color]<br />
[font=Menlo][size=2]<br />
[color=#3d8389]inputStream[/color] = ([color=#7c1fae]NSInputStream[/color] *)readStream;[/size][/font][font=Menlo][size=2]<br />
[color=#3d8389]outputStream[/color] = ([color=#7c1fae]NSOutputStream[/color] *)writeStream;[/size][/font][color=#3D8389][font=Menlo][size=2]<br />
[color=#000000][[/color]inputStream[color=#000000] [/color][color=#460085]setDelegate[/color][color=#000000]:[/color][color=#cd00a5]self[/color][color=#000000]];[/color][/size][/font][/color][color=#3D8389][font=Menlo][size=2]<br />
[color=#000000][[/color]outputStream[color=#000000] [/color][color=#460085]setDelegate[/color][color=#000000]:[/color][color=#cd00a5]self[/color][color=#000000]];[/color][/size][/font][/color][color=#460085][font=Menlo][size=2]<br />
[color=#000000][[/color][color=#3d8389]inputStream[/color][color=#000000] [/color]scheduleInRunLoop[color=#000000]:[[/color][color=#7c1fae]NSRunLoop[/color][color=#000000] [/color]currentRunLoop[color=#000000]] [/color]forMode[color=#000000]:[/color][color=#7c1fae]NSDefaultRunLoopMode[/color][color=#000000]];[/color][/size][/font][/color][color=#460085][font=Menlo][size=2]<br />
[color=#000000][[/color][color=#3d8389]outputStream[/color][color=#000000] [/color]scheduleInRunLoop[color=#000000]:[[/color][color=#7c1fae]NSRunLoop[/color][color=#000000] [/color]currentRunLoop[color=#000000]] [/color]forMode[color=#000000]:[/color][color=#7c1fae]NSDefaultRunLoopMode[/color][color=#000000]];[/color][/size][/font][/color][color=#3D8389][font=Menlo][size=2]<br />
[color=#000000][[/color]inputStream[color=#000000] [/color][color=#460085]open[/color][color=#000000]];[/color][/size][/font][/color][color=#3D8389][font=Menlo][size=2]<br />
[color=#000000][[/color]outputStream[color=#000000] [/color][color=#460085]open[/color][color=#000000]];[/color][/size][/font][/color][color=#3D8389][font=Menlo][size=2]<br />
[color=#000000]}[/color][/size][/font][/color]<br />
<br />








Jusque-là , pas de soucis.



Pour gérer tout ça, dans ma classe qui est NSStreamDelegate, j'ai mis :

[/size][/font][font=Menlo][size=2]<br />
-([color=#cd00a5]void[/color])stream:([color=#7c1fae]NSStream[/color] *)aStream handleEvent:([color=#7c1fae]NSStreamEvent[/color])eventCode[/size][/font][font=Menlo][size=2]<br />
{[/size][/font][color=#008C00][font=Menlo][size=2]<br />
[color=#CD00A5]   [/color][color=#CD00A5]switch[/color] (eventCode)[/size][/font][/color][font=Menlo][size=2]<br />
[color=#CD00A5]   [/color]{[/size][/font][color=#008C00][font=Menlo][size=2]<br />
//[..] Code retiré[/size][/font][/color]<br />
[color=#460085][font=Menlo][size=2]<br />
[color=#CD00A5]   [/color][color=#CD00A5]   [/color][color=#CD00A5]case[/color][color=#000000] [/color]NSStreamEventErrorOccurred[color=#000000]:[/color][/size][/font][/color][color=#E40000][font=Menlo][size=2]<br />
[color=#CD00A5]   [/color][color=#CD00A5]   [/color][color=#CD00A5]   [/color][color=#460085]NSLog[/color][color=#000000]([/color]@&quot;NSStreamEventErrorOccurred&quot;[color=#000000]);[/color][/size][/font][/color][font=Menlo][size=2]<br />
[color=#CD00A5]   [/color][color=#CD00A5]   [/color][color=#CD00A5]   [/color][color=#7C1FAE]NSError[/color] *error = [aStream [color=#460085]streamError[/color]];[/size][/font][color=#E40000][font=Menlo][size=2]<br />
[color=#CD00A5]   [/color][color=#CD00A5]   [/color][color=#CD00A5]   [/color][color=#460085]NSLog[/color][color=#000000]([/color]@&quot;StreamError : %@&quot;[color=#000000], error);[/color][/size][/font][/color]<br />
[color=#225A5F][font=Menlo][size=2]<br />
[color=#CD00A5]   [/color][color=#CD00A5]   [/color][color=#CD00A5]   [/color][color=#000000][[/color][color=#CD00A5]self[/color][color=#000000] [/color]closeNetWork[color=#000000]];[/color][/size][/font][/color][color=#CD00A5][font=Menlo][size=2]<br />
      break[color=#000000];[/color][/size][/font][/color][color=#CD00A5][font=Menlo][size=2]<br />
[color=#008C00]//[..] Code retiré[/color][/size][/font][/color]<br />
[font=Menlo][size=2]<br />
[color=#CD00A5]   [/color]}[/size][/font][font=Menlo][size=2]<br />
}[/size][/font]<br />




[/size][/font]<br />
[font=Menlo][size=2]-([/size][/font][color=#CD00A5][font=Menlo][size=2]void[/size][/font][/color][font=Menlo][size=2])closeNetWork[/size][/font]<br />
[font=Menlo][size=2]{[/size][/font]<br />
[color=#460085][font=Menlo][size=2]    NSLog[/size][/font][/color][color=#000000][font=Menlo][size=2]([/size][/font][/color][color=#E40000][font=Menlo][size=2]@&quot;Controlleurs closeNetWork&quot;[/size][/font][/color][color=#000000][font=Menlo][size=2]);[/size][/font][/color]<br />
<br />
<br />
[color=#3D8389][font=Menlo][size=2]<br />
[color=#cd00a5]if[/color][color=#000000] ([/color]inputStream[color=#000000])[/color][/size][/font][/color][font=Menlo][size=2]<br />
{[/size][/font][color=#3D8389][font=Menlo][size=2]<br />
[color=#000000]    [[/color]inputStream[color=#000000] [/color][color=#460085]close[/color][color=#000000]];[/color][/size][/font][/color][color=#460085][font=Menlo][size=2]<br />
[color=#000000]    [[/color][color=#3d8389]inputStream[/color][color=#000000] [/color]removeFromRunLoop[color=#000000]:[[/color][color=#7c1fae]NSRunLoop[/color][color=#000000] [/color]currentRunLoop[color=#000000]] [/color]forMode[color=#000000]:[/color][color=#7c1fae]NSDefaultRunLoopMode[/color][color=#000000]];[/color][/size][/font][/color][color=#E40000][font=Menlo][size=2]<br />
[color=#460085]    NSLog[/color][color=#000000]([/color]@&quot;inputStream status : %u&quot;[color=#000000], [/color][color=#3d8389]inputStream[/color][color=#000000].[/color][color=#460085]streamStatus[/color][color=#000000]);[/color][/size][/font][/color][color=#3D8389][font=Menlo][size=2]<br />
[color=#000000]    [[/color]inputStream[color=#000000] [/color][color=#460085]setDelegate[/color][color=#000000]:[/color][color=#cd00a5]nil[/color][color=#000000]];[/color][/size][/font][/color][color=#3D8389][font=Menlo][size=2]<br />
[color=#000000]    [[/color]inputStream[color=#000000] [/color][color=#460085]release[/color][color=#000000]];[/color][/size][/font][/color][color=#3D8389][font=Menlo][size=2]<br />
    inputStream[color=#000000] = [/color][color=#cd00a5]nil[/color][color=#000000];[/color][/size][/font][/color][font=Menlo][size=2]<br />
}[/size][/font][color=#3D8389][font=Menlo][size=2]<br />
[color=#cd00a5]if[/color][color=#000000] ([/color]outputStream[color=#000000])[/color][/size][/font][/color][font=Menlo][size=2]<br />
{[/size][/font][color=#3D8389][font=Menlo][size=2]<br />
[color=#000000]    [[/color]outputStream[color=#000000] [/color][color=#460085]close[/color][color=#000000]];[/color][/size][/font][/color][color=#460085][font=Menlo][size=2]<br />
[color=#000000]    [[/color][color=#3d8389]outputStream[/color][color=#000000] [/color]removeFromRunLoop[color=#000000]:[[/color][color=#7c1fae]NSRunLoop[/color][color=#000000] [/color]currentRunLoop[color=#000000]] [/color]forMode[color=#000000]:[/color][color=#7c1fae]NSDefaultRunLoopMode[/color][color=#000000]];[/color][/size][/font][/color][color=#E40000][font=Menlo][size=2]<br />
[color=#460085]    NSLog[/color][color=#000000]([/color]@&quot;outputStream status : %u&quot;[color=#000000], [/color][color=#3d8389]outputStream[/color][color=#000000].[/color][color=#460085]streamStatus[/color][color=#000000]);[/color][/size][/font][/color][color=#3D8389][font=Menlo][size=2]<br />
[color=#000000]    [[/color]outputStream[color=#000000] [/color][color=#460085]setDelegate[/color][color=#000000]:[/color][color=#cd00a5]nil[/color][color=#000000]];[/color][/size][/font][/color][color=#3D8389][font=Menlo][size=2]<br />
[color=#000000]    [[/color]outputStream[color=#000000] [/color][color=#460085]release[/color][color=#000000]];[/color][/size][/font][/color][color=#3D8389][font=Menlo][size=2]<br />
    outputStream[color=#000000] = [/color][color=#cd00a5]nil[/color][color=#000000];[/color][/size][/font][/color][font=Menlo][size=2]<br />
}[/size][/font]<br />
[font=Menlo][size=2]<br />
}[/size][/font]




En effet, si j'ai une erreur, et j'en ai (pour diverses raisons : Broken Pipe, etc.), j'ai envie de fermer la connexion.



Cependant, après cette fermeture de connexion, j'ai quand même envie de la relancer. Et là , ça bloque...

Par contre, si je quitte mon application et que je la relance (elle ne fonctionne pas en BackGround, du coup, ça la "kill" plus ou moins), là , pas de soucis, j'arrive sans problème à  avoir une connexion qui ne passe pas par NSStreamEventErrorOccured.



Pourquoi est-ce que je fais ça ?

J'essaye de communiquer avec un appareil distant, mais ce dernier, ce couillon ne peut accepter qu'une connexion à  la fois (ne me demandez pas, je tuerais le fabricant si je le pouvais tellement cela fait de temps que je perds du temps dessus à  ne rien comprendre du pourquoi du comment, alors qu'avant il en acceptait plusieurs !). Du coup, lorsque je connecte un second iDevice dessus, je me fais rejeter alors que pour le premier, tout est nickel. Normal. Puis, avec ce second iDevice, je rentre plus ou moins dans une boucle infinie de initNetworkCommunication et de closeNetwork (via pop-up/action de l'utilisateur) car j'ai un NSStreamEventErrorOccured. Mais lorsque l'iDevice qui était connecté dessus s'en va, je devrais en théorie retrouver la main dessus, non ? Sauf que... et bien non. Je continue de tomber sans cesse sur un NSStreamEventErrorOccured. Du coup, je suis obligé de killer l'application pour réellement avoir la main dessus.

Donc j'ai l'impression que je ne ferme pas bien un truc. Et je n'arrive pas à  déterminer quoi.

J'ai trouvé sur le web quelques trucs en parlant, et les samples que je trouve ne gère pas vraiment la déconnexion (même le p'tit SimpleFTPSample d'Apple).

Bon, et si c'était ce fichu module qui merdait, hein ? Et bien, sous Android (bouh les robots !), mon collègue n'a pas ce soucis. Du coup, la piste du " y'a un truc qui n'a pas bien voulu se fermer, une sorte de port déjà  occupé où je ne sais quoi " devient plus que plausible, un truc qui demande que l'OS kill l'application...

Réponses

  • Ce que tu fais semble correct.



    Tu pourrais essayer de ne pas faire le removeFromRunLoop quand tu closes les streams. L'hypothese etant que les streams ont peut etre besoin de quelques coup de run loop supplementaire pour fermer correctement les sockets sous jacentes.



  • Meric pour l'´hypothèse, je vais vor ça...
  • LarmeLarme Membre
    décembre 2012 modifié #4
    Après relecture de la Doc Apple, il font bien le removeFromRunLoop.



    J'isole plus le problème.

    Un des NSXxXStream reçoit en error :

    StreamError : Error Domain=NSPOSIXErrorDomain Code=32 "The operation couldn't be completed. Broken pipe"



    Et lorsque je tente de les fermer, celui qui a reçu l'erreur est au statut : NSStreamStatusError[font=Courier, Consolas, monospace] = 7[/font]

    Alors que les autres sont bien au statut : NSStreamStatusClosed[font=Courier, Consolas, monospace] = 6.[/font]
  • Bon, j'ai aussi un beau :



    StreamError : Error Domain=NSPOSIXErrorDomain Code=54 "The operation couldn't be completed. Connection reset by peer" UserInfo=0x251bf0 {}



    Je suppose que demander à  l'utilisateur de redémarrer l'application n'est pas acceptable pour Apple...
  • J'ai vu ça cet après-midi, mais y'a pas de réinitialisation de la connexion...

    Dans d'autres exemples, il le retire de la runLoop (même si apparemment, un close suffit), et un nil ensuite...

    Ce que je fais, via la même méthode, mais ça ne veut pas...
  • Ce que tu fais semble simple et correct donc cela doit venir de l'autre.

    Est-ce que tu ne ré-essayes pas trop vite de te connecter à  l'autre. L'hypothèse étant que l'autre serait encore dans un timeout lié à  son envoi ou à  sa réception...

    Si tu éteins et rallume le périphérique en face après une erreur et ce que tu as toujours des problèmes ?
  • Si j'éteins mon périphérique, et bien, je reste sur ce problème tant que je ne redémarre pas l'application.

    D'après les tests effectués, lorsque j'arrive en out of range, il ne veut pas se reconnecter : boucle infinie des initNetwork & closeNetwork.
  • J'ai regardé le code de GCDAsyncSocket et de AsyncSocket.

    Le retrait de la run loop est bien fait mais la différence avec ton code, c'est que le retrait est fait avant le close.

    En fait dans l'ordre, ils font :



    CFReadStreamUnscheduleFromRunLoop



    CFReadStreamSetClient à  NULL, un peu l'équivalent de mettre le delegate à  nil dans ton cas je pense.



    CFReadStreamClose

    CFRelease
  • LarmeLarme Membre
    décembre 2012 modifié #11
    Bon, l'application a été validée telle quelle (j'avais des p*t**ns de contraintes de deadlines avec des produits qui restaient dans des warehouses sans pouvoir se vendre...).

    Mais je ne vous oublie pas. Il faudra de toute manière retravailler cette application pour diverses raisons : Multi-trheading plus performant, Connexion, Rajout de langues, etc. Je reviendrais upper ce topic, et si je trouve la solution, je ne devrais pas oublier de la mettre, ça aidera sûrement certains qui ne veulent pas utiliser de bibliothèque annexes quand ils veulent juste faire 2-3 sockets toutes bêtes.
  • Merci beaucoup pour ce très bon post :-)



    Je suis actuellement sur le même problème où ça fait 3 jours que je me prend la tête dessus image/crybaby.gif' class='bbc_emoticon' alt=' :'( ' />



    J'ai aussi un autre problème, c'est la libération du serveur lorsque je quitte mon application, j'y arrive pas image/crazy.gif' class='bbc_emoticon' alt=' B) ' />



    Une tite aide pour cette fin de journée??? image/implore.gif' class='bbc_emoticon' alt=' o:) ' />
  • Pourrais-tu te présenter dans le forum adéquat ? Cela nous aiderait d'avoir ton background (connaissance en objective-c, POO en général, etc.)



    Sinon, si tu fais un close, ça ne ferme pas du côté de ton serveur ?
  • image/thumbsup.gif' class='bbc_emoticon' alt='' /> oui pas de soucis enfin c'est finalement terminé le soucis image/cliccool.gif' class='bbc_emoticon' alt=' :p ' />



    En faite, je ne déterminais pas de la taille du buffer ce qui le faisait tourner à  l'infini mais maintenant c'est bon image/clap.gif' class='bbc_emoticon' alt=' :D ' />



    Je n'hésiterais pas à  revenir vers toi si je trouve ton problème même si ton client n'a rien vu image/evil.gif' class='bbc_emoticon' alt='>:D' />
  • 'stitch001' a écrit:
    Je n'hésiterais pas à  revenir vers toi si je trouve ton problème même si ton client n'a rien vu image/evil.gif' class='bbc_emoticon' alt='>:D' />/>


    Le client est conscient du soucis (enfin vaguement au point de vue technique, mais il sait qu'il existe).
Connectez-vous ou Inscrivez-vous pour répondre.