2010-11-18 4 views
2

Je suis nouveau à delphi et ceci est mon premier projet. est ici un peu de code:Connexion fermée gracieusement lorsque IdTCPClient.IOHandler.ReadStream()!

procedure TForm1.Button2Click(Sender: TObject); 
responseStringFromServer:TStringStream; 
begin 
try 
    if IdTCPClient1.Connected then 
    begin 
    dataSentToDevice:= 'http/1.0 content-length: 344 content-type: text/xml <?xml   version="1.0" encoding="UTF-8" ?> ...' 
    IdTCPClient1.IOHandler.WriteLn(dataSentToDevice); 
    responseStringFromServer := TStringStream.Create; 
    IdTCPClient1.IOHandler.ReadStream(responseStringFromServer); 
    ... 

J'ai un appareil connecté au réseau local. Je parviens à me connecter avec succès. L'envoi de commandes travaille aussi, mais quand je fais

IdTCPClient1.IOHandler.ReadStream(responseStringFromServer); 

il attend jusqu'à ce dispositif se fait le traitement et une exception se produit: « Connexion refermées ». Donc, je ne suis pas capable de lire les données que l'appareil est censé m'envoyer. L'appareil ne s'arrête pas. J'ai lu d'autres articles et je comprends que l'appareil lui-même supprime la connexion. J'ai un programme de démo qui communique avec lui et ça fonctionne très bien. J'ai besoin d'obtenir une réponse xml avant de laisser tomber la connexion.

Aussi la demande est http et j'utilise IdTCPClient (j'ai besoin d'utiliser la requête XML, je ne sais pas comment le faire avec TidHTTP). Peut-être qu'après que le périphérique envoie une réponse, il abandonne la connexion, de sorte que mon tcpclient obtienne un indicateur de connexion interrompue avant de recevoir des données.

Toute aide serait appréciée!

+0

S'il y a un programme de démonstration qui fonctionne bien, j'utiliserais un sniffer de réseau (WireShark) pour voir ce qu'il fait et ensuite comparer le flux de communication avec l'application Delphi. Un proxy HTTP comme Don's Proxy http://donsproxy.moneybender.com/ peut également être utilisé - peut-être plus facile que le sniff réseau. – mjn

+0

Convenu. Si vous n'avez pas de documentation pour le protocole actuel de l'appareil, alors un renifleur de paquets est la meilleure chose à faire. –

Répondre

1

Aussi la demande est http et je suis à l'aide IdTCPClient (j'utiliser demande xml , je ne sais pas comment le faire avec TidHTTP).

Travailler avec IdHTTP est simple ...

  1. Mettez une instance sur votre formulaire, sélectionnez-le.
  2. Dans l'inspecteur d'objets, accédez à la propriété ProtocolVersion, et mettez- à pv1_0, puis ouvrez le
  3. Demande ensemble de propriétés et définissez Request.ContentType text/xml, et Request.ContentEncoding UTF-8 , et définir d'autres propriétés si requis. Ajouter un bouton à votre formulaire et double-cliquez dessus.
  4. Dans votre code, créez une instance de TStringStream et chargez-y votre contenu XML . Attribuer votre flux à IdHttp.Request.Source.
  5. Appelez la méthode IdHttp.Get() en lui attribuant une adresse hôte .
  6. IdHttp.Get() renvoie une chaîne dont la réponse est .
+0

UTF-8 n'est pas une valeur de propriété ContentEncoding valide. Vous pensez à la propriété CharSet à la place. En outre, il n'y a pas de propriété Request.Stream. Vous passez un flux d'entrée directement à Post() dans son paramètre ASource à la place (pour envoyer des données d'entrée avec une requête GET, vous devez appeler DoRequest() directement). En outre, je recommande d'utiliser un TMemoryStream au lieu d'un TStringStream, car TStringStream a changé dans D2009 pour prendre en charge Unicode et vous ne voulez pas qu'il gâche les données XML par accident. –

+0

ok, envoyer des données avec idhttp fonctionne très bien. J'ai toujours un problème pour récupérer les données de l'appareil avec la procédure IdHttp.get(). Maintenant, il s'arrête à IdHttp.get() et attend un moment. Ensuite, il lève l'exception EIdConnClosedGracefully. Existe-t-il un meilleur moyen de demander des données ou comment fonctionne idhttp.get()? pour le moment j'utilise IdHTTP1.Get ('http: // deviceIP: port', réponse); La réponse est le type de TMemoryStream. Y at-il un moyen de spécifier l'heure de retour quand il devrait cesser d'attendre la réponse? – Peacelyk

+0

OK, il s'est avéré que je devais écouter un autre port. pas celui auquel j'envoyais des données. Mais ça ne marche toujours pas correctement: maintenant, quand j'appelle la procédure idhttp.get(), alors il reste juste là jusqu'à ce que le timeout arrive. Dois-je commencer à écouter le port avant d'envoyer les données ou est-ce suffisant quand je commence à écouter le port juste après que j'ai envoyé les données? – Peacelyk

2

La façon dont vous appelez ReadStream(), il interprétera les 4 premiers octets (ou 8 octets si la propriété est TIdIOHandler.LargeStream True) comme un entier (ou Int64) pour réseau octets qui spécifie le longueur des données, puis il va essayer de lire autant d'octets. L'appareil envoie-t-il réellement une valeur de longueur? Si ce n'est pas le cas, ReadStream() tentera de lire le mauvais nombre d'octets. Une exception EIdConnClosedGracefully signifie que le périphérique ferme le socket à son extrémité.Ainsi, soit le périphérique ferme la connexion immédiatement après l'envoi de ses données, soit il attend l'envoi de la commande suivante, ce que vous ne pouvez pas faire car vous êtes bloqué en attendant les mauvaises données de la commande précédente.

0

Comme l'a dit @Remy Lebeau et la documentation (appuyez sur F1 lorsque votre édition caret est sur la phrase ReadStream):

AByteCount indique le nombre d'octets de la IOHandler à lire dans AStream. Lorsque AByteCount contient -1 et que AReadUntilDisconnect contient False, le nombre d'octets est lu comme une valeur Integer à partir du IOHandler. La taille d'AStream est ajustée pour correspondre à la taille attendue de l'IOHandler.

Ceci est très utile lorsque vous vous connectez à des serveurs écrits aussi dans INDY WriteStream à une extrémité, ReadStream dans l'autre, ou toute autre langue si vous envoyez que cound octets comme prévu par le client INDY.

Si vous lisez un appareil , assurez-vous que l'appareil envoie ces informations directement au flux ou modifiez la façon dont vous lisez les données. Si vous connaissez la taille du flux, passez simplement le second paramètre: AByteCount. Si le périphérique ferme le canal à la fin du flux, transmettez -1 comme second paramètre et True comme troisième paramètre: AReadUntilDisconnect.

Si le périphérique envoie un texte de longueur inconnue mais utilise un terminateur connu (comme CR/LF), il vaut mieux utiliser la méthode ReadLn de IOHandler pour obtenir cette chaîne.

Jetez un oeil à si ni à vos besoins, jetez un oeil sur Lire * méthodes de TIOHandlerClass et RTFM pour chacun de trouver le bon pour obtenir les données envoyées par l'appareil .