Page 1 sur 2
[..] Grandes données TCP
Posté : dim. 20 nov. 2011 12:29
par Tetdoss
Salut à tous, j'ai essayé de créer 2 fonctions : send_data et recv_data pour recevoir et envoyer des données avec le protocole TCP.
Voici ma fonction send_data
Code : Tout sélectionner
Func send_data($socket, $data)
$data = Chr(2) & $data & Chr(3)
$data = _Crypt_EncryptData($data, $CALG_3DES, "Tetdoss")
Return TCPSend($socket, $data)
EndFunc
J'ai "encadré" ma donnée avec Chr(2) et Chr(3)
Je voudrais pouvoir récupérer à l'octet près, cette donnée, sachant chaque "bout" (packet) de donnée reçue fait 2048 octets...
Voilà je sais pas trop si c'est faisable mais ça me permettra de gérer l'envoie de n'importe quel fichier, même ceux supérieur à 2048 octets !
En espérant m'avoir fait comprendre, merci d'avance !
Re: [..] Grandes données TCP
Posté : dim. 20 nov. 2011 14:13
par Tetdoss
Bon j'ai réfléchi et j'ai pensé à une autre méthode, mettre dans l'en-tête d'un paquet la taille de la donnée. Mais il faudrait que cet en-tête ait toujours la même taille... Je pense que c'est la meilleure des solutions.
Je vais essayer de réfléchir là-dessus en attendant.
Je pense à quelque chose de ce genre :
Code : Tout sélectionner
Func send_data($socket, $data)
$data = _Crypt_EncryptData($data, $CALG_3DES, "Tetdoss")
$len = BinaryLen($data)
$data = $len & $data
Return TCPSend($socket, $data)
EndFunc
Func recv_data($socket)
$len = TCPRecv($socket, 8)
$data = TCPRecv($socket, $len)
$data = _Crypt_DecryptData($data, $CALG_3DES, "Tetdoss")
Return $data
EndFunc
Mais comment puis-je être sûr que $len est de 8 octets... J'ai fait des tests et en fonction du nombre, c'est 4 ou 8 ^^
Re: [..] Grandes données TCP
Posté : dim. 20 nov. 2011 14:14
par Iste
attendez, je ne suis aps sur de comprendre.
les fonctions TCP d'AutoIt font déja tout le boulot
Vous n'avez pas a vous préoccuper des entête et des paquet.
Pouvez vous nous donner un cas concret de votre probleme, si possible dans un mini projet de test préconstruit ?
Re: [..] Grandes données TCP
Posté : dim. 20 nov. 2011 14:17
par Tetdoss
Salut merci de ta réponse Iste, en fait je voudrais faire un code sans me soucier du paramètre $maxlen de TCPRecv, je voudrais obtenir à chaque fois, toute la donnée $data, qu'elle soit grosse ou non.
Re: [..] Grandes données TCP
Posté : dim. 20 nov. 2011 14:22
par Iste
Votre connexion est ponctuelle (ouverture, envoi, fermeture) ou continue ?
Dans le 1er cas, inspirez vous simplement de l'exemple de la doc ou de ceux du forum.
$maxlen ne dit pas "attention, tu vas recevoir xxx byte" mais "bon, envoi les xxx prochain byte"
on procède ainsi, car il est rare que tout les byte soient arrivés lors du traitement.
Du coup, il nous faut juste une boucle, qui va faire des TCPRecv() de quelque caractères (a vous de voir combien, 4000semble cool) et les ajouter a un buffer. Des que TCPRecv() renvoi une erreur, c'est qu'on en a fini, notre buffer contient notre info.
Pour le cas d'une connexion continue, ca sera un peu plus complexe, mais dans la meme idée.
Re: [..] Grandes données TCP
Posté : dim. 20 nov. 2011 14:28
par Tetdoss
Ahah

ça m'a l'air pas mal comme ça !
Biensûr ma connexion est ponctuelle, j'avais complètement oublié la return value de TCPRecv, en fait la maxlen c'est juste la taille d'un bout de la donnée.
Je crois avoir compris, j'essaie et je vous tiens au courant

.
PS : C'est la première fois que je me mets aux réseaux alors j'ai un peu de mal ^^
Et c'est cool que TCP gère les en-têtes !
Re: [..] Grandes données TCP
Posté : dim. 20 nov. 2011 14:42
par Tetdoss
Voilà j'ai fait quelque chose comme ça :
Code : Tout sélectionner
Func send_data($socket, $data)
$data = _Crypt_EncryptData($data, $CALG_3DES, "Tetdoss")
Return TCPSend($socket, $data)
EndFunc
Func recv_data($socket)
While 1
If ($data = TCPRecv($socket, 2048)) Then
$buffer = $buffer & $data
Else
ExitLoop
EndIf
WEnd
$buffer = _Crypt_DecryptData($buffer, $CALG_3DES, "Tetdoss")
Return $buffer
EndFunc
Je n'ai pas encore l'occasion de tester ce code mais quand je le ferai, je passerai ce sujet résolu (si ça marche biensûr)
Re: [..] Grandes données TCP
Posté : dim. 20 nov. 2011 15:11
par matwachich
Juste au cas ou, j'ai fait exactement la même chose dans
mon UDF, vous pouvez envoyer n'importe quelle fichier, données binaire, ou chaîne de caractère!
D'ailleur, le Chr(2) --- Chr(3) me dis quelque chose...
Pour répondre à votre question, regardez la fonction
__TCPServer_SocketCheckBuffer dans le fichier TCPServer.au3
Re: [..] Grandes données TCP
Posté : dim. 20 nov. 2011 18:27
par Tetdoss
Merci beaucoup pour ton UDF, j'ai bien étudié ton UDF en OO et l'autre.
J'ai choisi celui que tu viens de me montrer, car je n'aime pas mélanger de la POO avec de la programmation sans objets

. De toute façon, même celui que tu viens de me passer ressemble à de la POO avec toutes ces variables globales

.
Enfin bref, j'ai pris du temps à comprendre comment il fonctionnait et je crois que je suis parti là , je verrais juste comment faire pour envoyer des données contenant plusieurs "sections"
Re: [..] Grandes données TCP
Posté : dim. 20 nov. 2011 20:23
par Tetdoss
J'ai un problème dans ton UDF :
E:\Documents\Programmation\AutoIt\SDK\AutoIt3\Include\SimpleTCP\TCPServer.au3 (530) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
$ret[$ret[0] + 1][0] = $__TCPServer_Sockets[$i][0]
$ret[^ ERROR
>Exit code: 1 Time: 7.915
Le problème vient de cette fonction :
Code : Tout sélectionner
Func _TCPServer_SocketList()
If Not _TCPServer_IsStarted() Then Return SetError(-1, 0, 0)
; ---
Local $ret[1][2] = [[0,""]]
; ---
For $i = 1 To $__TCPServer_Sockets[0][0]
If $__TCPServer_Sockets[$i][0] <> -1 Then
ReDim $ret[$ret[0][0] + 2][2]
$ret[$ret[0] + 1][0] = $__TCPServer_Sockets[$i][0]
$ret[$ret[0] + 1][1] = $__TCPServer_Sockets[$i][1]
$ret[0][0] += 1
EndIf
Next
; ---
Return $ret
EndFunc
Edit : il manque 2 [0] dans cette fonction je crois, ce n'est pas $ret[0] mais $ret[0][0]
Re: [..] Grandes données TCP
Posté : dim. 20 nov. 2011 20:36
par matwachich
En effet, merci de retour!
La fonction correct est:
Code : Tout sélectionner
Func _TCPServer_SocketList()
If Not _TCPServer_IsStarted() Then Return SetError(-1, 0, 0)
; ---
Local $ret[1][2] = [[0,""]]
; ---
For $i = 1 To $__TCPServer_Sockets[0][0]
If $__TCPServer_Sockets[$i][0] <> -1 Then
ReDim $ret[$ret[0][0] + 2][2]
$ret[$ret[0][0] + 1][0] = $__TCPServer_Sockets[$i][0]
$ret[$ret[0][0] + 1][1] = $__TCPServer_Sockets[$i][1]
$ret[0][0] += 1
EndIf
Next
; ---
Return $ret
EndFunc
Je met à jour le Sujet d'origine.
Re: [..] Grandes données TCP
Posté : lun. 21 nov. 2011 21:31
par Tetdoss
J'avance j'avance

J'ai trouvé une autre erreur je crois bien.
Lors de du Func _TCPServer_Process(), tu fais des Call en envoyant $i en 2ème paramètre :
Call($__TCPSrv_Info_CB_LOST, $i, $__TCPServer_Sockets[$i][1])
Or c'est plutôt $__TCPServer_Sockets[$i][0] qui nous intéresse, car c'est la VRAIE ID du client. Ton exemple est alors faut car tu fais dans Func _TCP_Recv($iSocket, $sIP, $Data) :
Local $nick = _TCPServer_ClientPropertyGet($iSocket, 0)
Mais je peux me tromper car ce n'est pas mon UDF.
PS : Ce que j'appelle VRAIE ID, c'est par exemple 689 ou 742.
En passant, cette ID peut-elle être égale à 0 ? Car j'initialise $client_id (ma variable contenant le client principal de mon prog) à 0 
j'ai trouvé, la VRAIE ID c'est le retour de TCPListen

et donc je crois bien que tu t'es trompé.
Ma correction :
► Afficher le texte
Code : Tout sélectionner
Func _TCPServer_Process()
If Not _TCPServer_IsStarted() Then Return SetError(-1, 0, 0)
; ---
Local $hNewSocket, $recv, $tmp
; ---
; Check new connexions
$hNewSocket = TCPAccept($__TCPSrv_Info_SOCKET)
If $hNewSocket <> -1 Then
__TCPServer_StoreNewClient($hNewSocket)
EndIf
; ---
; Process Connected clients
For $i = 1 To $__TCPServer_Sockets[0][0]
If $__TCPServer_Sockets[$i][0] = -1 Then ContinueLoop
; ---
$recv = TCPRecv($__TCPServer_Sockets[$i][0], 4096)
; ---
; Check disconnection
If @error Then
If $__TCPSrv_Info_CB_LOST <> "" Then _
Call($__TCPSrv_Info_CB_LOST, $__TCPServer_Sockets[$i][0], $__TCPServer_Sockets[$i][1])
; ---
TCPCloseSocket($__TCPServer_Sockets[$i][0])
__TCPServer_ResetSocket($i)
EndIf
; ---
; Check Receiving
If $recv Then
$__TCPServer_Sockets[$i][3] = TimerInit()
$__TCPServer_Sockets[$i][2] &= $recv
; ---
If $__TCPSrv_Info_CB_RECEIVING <> "" Then _
Call($__TCPSrv_Info_CB_RECEIVING, $__TCPServer_Sockets[$i][0], $__TCPServer_Sockets[$i][1], BinaryLen($__TCPServer_Sockets[$i][2]))
EndIf
; ---
; Check timeout
If $__TCPServer_Sockets[$i][2] Then
If TimerDiff($__TCPServer_Sockets[$i][3]) >= $__TCPSrv_Info_TIMEOUT Then ; Timed-out!
If $__TCPSrv_Info_CB_TIMEDOUT <> "" Then _
Call($__TCPSrv_Info_CB_TIMEDOUT, $__TCPServer_Sockets[$i][0], $__TCPServer_Sockets[$i][1], BinaryLen($__TCPServer_Sockets[$i][2]))
; ---
$__TCPServer_Sockets[$i][2] = ""
EndIf
EndIf
; ---
; Check buffer
$tmp = __TCPServer_SocketCheckBuffer($i)
If IsArray($tmp) Then
For $elem In $tmp
If $__TCPSrv_Info_CB_RECV <> "" Then _
Call($__TCPSrv_Info_CB_RECV, $__TCPServer_Sockets[$i][0], $__TCPServer_Sockets[$i][1], $elem)
Next
; ---
$__TCPServer_Sockets[$i][2] = ""
EndIf
Next
; ---
Return 1
EndFunc
Re: [..] Grandes données TCP
Posté : lun. 21 nov. 2011 21:53
par matwachich
Noooooooooooooooon attention!!!!
Le SocketID de mon UDF n'a
RIEN à voir avec le hSocket des fonctions TCP d'AutoIt!
Au début, c'était comme cela, après je me suis rendu compte que c'est bien mieux ainsi, en terme de performances et de simplicité de gestion.
Alors SVP, ne touchez pas à ça!!!
PS: d'ailleur, pour s'en rendre compte, il n'y a qu'à remarquer l'existance des fonctions:
_TCPServer_SocketID2SocketHandle et
_TCPServer_SocketHandle2SocketID
Re: [..] Grandes données TCP
Posté : lun. 21 nov. 2011 22:03
par Tetdoss
Bah alors le socket ID que je prends avec le socket list n'est pas bon ?? Car moi j'ai l'ID de retour de TCPListen à chaque fois.
PS : voir au-dessus pour socket list
Re: [..] Grandes données TCP
Posté : lun. 21 nov. 2011 22:10
par matwachich
Aie!

J'me suis fait prendre en flagrant délit de non concentration!!!
Et une nouvelle version! Correction dans le post d'origine de SimpleTCP
► Afficher le texteFonction _TCPServer_SocketList Corrigée
Code : Tout sélectionner
Func _TCPServer_SocketList()
If Not _TCPServer_IsStarted() Then Return SetError(-1, 0, 0)
; ---
Local $ret[1][2] = [[0,""]]
; ---
For $i = 1 To $__TCPServer_Sockets[0][0]
If $__TCPServer_Sockets[$i][0] <> -1 Then
ReDim $ret[$ret[0][0] + 2][2]
$ret[$ret[0][0] + 1][0] = $i ; Corrected in 1.1.1
$ret[$ret[0][0] + 1][1] = $__TCPServer_Sockets[$i][1]
$ret[0][0] += 1
EndIf
Next
; ---
Return $ret
EndFunc
Un grand merci à vous!!!
Edit: Le SocketID de mon UDF commence à 1, pas à 0. Et n'utilisez pas de array contenant tous vos clients, utilisez plutôt les fonctionalitées de
_TCPServer_ClientsPropertyXXX, elle servent justement à ça, ne pas avoir à gérer de array soit même.
Re: [..] Grandes données TCP
Posté : lun. 21 nov. 2011 22:14
par Tetdoss
Ce n'est rien, je voyais bien qu'il y avait un mélange d'ID bizarre ^^ je vais tester ça.
EDIT : c'est beaucoup mieux maintenant

Re: [..] Grandes données TCP
Posté : lun. 21 nov. 2011 22:19
par Tetdoss
utilisez plutôt les fonctionalitées de _TCPServer_ClientsPropertyXXX
En fait je visualise tous mes clients dans une view list pour en choisir un seul donc pas besoin ^^

Re: [..] Grandes données TCP
Posté : lun. 21 nov. 2011 23:04
par Tetdoss
J'ai une question, je voudrais envoyer des données avec un séparateur par exemple "|". Le problème, c'est que je n'arrive pas à gérer le cas ou l'utilisateur décide d'envoyer une chaîne avec ce caractère, j'ai pensé à un StringReplace($data, "|", "||") mais ensuite, je voudrais récupérer toutes les chaînes entre 2 "|" mais StringSplit ne fonctionne pas ici, car il va prendre en compte les "||". Dois-je faire mon algorithme tout seul ou existe-t-il une fonction ? Ou alors avez-vous un algo à me proposer ?
C'est un truc à rajouter dans ton UDF matwachich
Merci.
Re: [..] Grandes données TCP
Posté : mar. 22 nov. 2011 00:15
par matwachich
Quand je veut faire ça, je sépare mes données par Chr(11).
Je l'utilise par exemple pour envoyer des fichiers, tout simplement! (plus simple, tu meurs!)
Envoyeur:
Code : Tout sélectionner
; ouvrir un fichier en mode binaire
$hFile = FileOpen("fichier", 16)
; lire le contenu
$data = FileRead($hFile)
FileClose($hFile)
; ensuite, on envoi tout simplement. (le file servira juste à dire que c'est un fichier)
_TCPServer_Send($iSocket, "file" & Chr(11) & $data)
En suite, le receveur:
Code : Tout sélectionner
; La fonction callback de reception
Func _TCP_Recv($iClient, $Data)
; vérifier si c'est un fichier
If StringLeft($Data, 5) = "file" & Chr(11) Then
$Data = StringSplit($Data, Chr(11))
; ouvrir un fichier en mode écriture binaire
$hFile = FileOpen("fichier", 18)
FileWrite($hFile, $Data[2])
FileClose($hFile)
Return
EndIf
; ---
; Sinon, si c'est pas un fichier, bah la c'est votre problème!
EndFunc
PS: à propos de StringSplit, lisez bien la doc, vous verrez qu'elle peut très bien diviser par "||" sans retourner le vide entre les 2 |, voyez le flag (dernier paramètre)
Re: [..] Grandes données TCP
Posté : mar. 22 nov. 2011 00:50
par matwachich
C'est un truc à rajouter dans ton UDF matwachich
Cadeau!