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 :
J'initialise ma connexion ainsi :
Jusque-là , pas de soucis.
Pour gérer tout ça, dans ma classe qui est NSStreamDelegate, j'ai mis :
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...
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]@"Entree dans initNetWorkCommunication"[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]@"192.168.11.123"[/color], [color=#3800df]2000[/color], &readStream, &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]@"NSStreamEventErrorOccurred"[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]@"StreamError : %@"[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]@"Controlleurs closeNetWork"[/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]@"inputStream status : %u"[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]@"outputStream status : %u"[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...
Mots clés:
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
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.
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]
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...
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Streams/Articles/HandlingStreamError.html#//apple_ref/doc/uid/20002276-BCIDDFHF
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...
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 ?
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.
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
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.
Je suis actuellement sur le même problème où ça fait 3 jours que je me prend la tête dessus /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 /crazy.gif' class='bbc_emoticon' alt=' ' />
Une tite aide pour cette fin de journée??? /implore.gif' class='bbc_emoticon' alt=' ' />
Sinon, si tu fais un close, ça ne ferme pas du côté de ton serveur ?
En faite, je ne déterminais pas de la taille du buffer ce qui le faisait tourner à l'infini mais maintenant c'est bon /clap.gif' class='bbc_emoticon' alt=' ' />
Je n'hésiterais pas à revenir vers toi si je trouve ton problème même si ton client n'a rien vu /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).