Bonjour,
Je ne maîtrise pas, loin s'en faut Indy. Je souhaite utiliser un serveur TCP pour une communication entre plusieurs process, 2 process clients, 1 process serveur, sur une même machine.
J'ai donc un serveur (TIdTcpServer) et 2 clients (TIdTcpClient).
L'idée est de créer un process serveur qui écoute sur 3 ports.
Le port 1 est utilisé pour la connexion initiale quand un client se connecte, port sur lequel le serveur lui renvoie un n° de port disponible.
Alors le client se déconnecte du port 1 et se reconnecte au port libre fourni précédemment.
Le but est aussi que le serveur puisse réagir quand un client se déconnecte, donc la connexion est permanente sur les ports 2 et 3 et du code est exécuté sur le serveur dans le "OnDisconnect" du serveur.
Pour schématiser on a SRV, CLT1, CLT2. On ne peut pas prédire si CLT1 démarre avant CLT2 ou inversement, et on veut pouvoir prévoir d'autre process clients si nécessaire à l'avenir.
SRV écoute sur les ports 1, 2 , 3
CLT1 démarre, se connecte au port 1, SRV lui renvoie le port libre 2, CLT1 se déconnecte du port 1 et se reconnecte au port 2 de façon permanente.
CLT2 démarre, se connecte au port 1, SRV lui renvoie le port libre 3, CLT2 se déconnecte du port 1 et se reconnecte au port 3 de façon permanente.
Est-ce une bonne approche ? Ou existe-t-il déjà un mécanisme similaire dans Indy ?
J'ai commencé à expérimenté. La communication entre SRV et CLT1 est ok.
En revanche, bien que le port 1 soit déconnecté, la connexion du client suivant CLT2 sur le port 1 semble poser problème.
La connexion n'est pas refusée, mais elle semble échouer après le timeout fixé. Que ce timeout soit de 500ms ou de 10 secondes ne change rien.
Code de connexion d'un client :
Code côté serveur:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 function TMes.Conn() : Boolean; const sname = 'TMes.Conn'; var NewPort : Word; SocketResponse : TSocketMsg; Begin result := false; clt.Connect; // Connexion au port 1 if IsCltConnected(Clt) then begin clt.IOHandler.WriteLn(SocketMsg(tcpGetPort, '', true).Str); // Demande de port libre SocketResponse := SocketMsg(clt.IOHandler.ReadLn); // Lecture du port fourni if clt.IOHandler.ReadLnTimedout then begin trace(logOnDebug, sname,'TIMEOUT CAS 1'); // Timeout : C'est un des deux traces que je trouve dans mon log quand CLT2 tente de se connecter... end; if SocketResponse.ok then begin NewPort := StrToInt(SocketResponse.What); clt.IOHandler.InputBuffer.clear; clt.Disconnect; // Déconnexion port 1 clt.Port := NewPort; clt.Connect; // Reconnexion au port fourni if IsCltConnected(Clt) then begin Clt.IOHandler.WriteLn(SocketMsg(tcpGetProcess, '', true).Str); try SocketResponse := SocketMsg(clt.IOHandler.ReadLn); if clt.IOHandler.ReadLnTimedout then begin trace(logOnDebug, sname,'TIMEOUT CAS 2'); // ..Ou c'est parfois celle-ci end; if SocketResponse.ok then begin result := true; end else begin clt.IOHandler.InputBuffer.clear; clt.Disconnect; end; except on e: Exception do begin clt.IOHandler.InputBuffer.clear; // Sinon pas de déconnexion ! clt.Disconnect(false); end; end; end else begin trace(logOnDebug, sname,'Connexion impossible'); end; end else begin trace(logOnDebug, sname,'Réponse invalide, déconnexion'); clt.IOHandler.InputBuffer.clear; // Sinon pas de déconnexion ! clt.Disconnect; end; end; end; function TMes.IsCltConnected (var Clt : TIdTcpClient) : boolean; const sname = 'TMes.IsCltConnected'; begin result := false; try result := clt.Connected; except on e : exception do begin try // Dans ce cas on passe False => on ne notifie pas la peer de la déconnexion puisque la peer est morte. clt.Disconnect(False); except on e : exception do begin trace(logOnRelease, sname,'==========================> EXCEPTION : '+ e.Message); end; end; if assigned(clt.IOHandler) then clt.IOHandler.InputBuffer.Clear; end; end; end;
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 procedure TMes.TcpSrvExecute(AContext: TIdContext); const sname = 'TMes.TcpSrvExecute'; Var i : integer; Msg, Response : TSocketMsg; begin Msg := SocketMsg(AContext.Connection.IOHandler.ReadLn); // Initialisation réponse : Qu'on enverra que si Msg.Wait Response := SocketMsg(tcpKo, '', false); trace(logOnRelease, sname,'Réception de ' + Msg.Str + ' Who=' + Msg.Who + ' Why=' + Msg.Why + ' What='+Msg.What + ' Wait='+StrLog(Msg.Wait)); // Demande de port if Msg.Why = tcpGetPort then begin trace(logOnDebug, sname,'Demande de port'); for i := 2 to tcpNbPort do begin // Port 1 = broker if not PortInUse[i].Used then begin PortInUse[i].Used := true; Response := SocketMsg(tcpOk, IntToStr(PortInUse[i].Port), false); break; end else begin trace(logOnDebug, sname,'Port ' + IntToStr(PortInUse[i].Port) + ' occupé'); end; end; end // Demande de nom de process pour contrôle else if Msg.Why = tcpGetProcess then begin trace(logOnDebug, sname,'Demande de Process'); Response := SocketMsg(tcpOk,GetWinProc(WHO_AM_I), false); end else begin trace(logOnDebug, sname,'TcpSrvExecute - "Why" inconnu ' + Msg.Why + ' What=' + Msg.What); end; // Renvoi ack et réponse if Msg.Wait then begin trace(logOnDebug, sname,'Renvoi de ' + Response.Str + ' Who=' + Response.Who + ' Why=' + Response.Why + ' What='+ Response.What + ' Wait=' + StrLog(Response.Wait)); AContext.Connection.IOHandler.WriteLn(Response.Str); end; end;
(Remarque : TMes = class(TThread))
Y-a-t-il un problème de déconnexion ? Ou est-ce un problème lié au fait que le CLT1 restant connecté au port 2, le SRV ne peut pas prendre en compte les demandes du CLT 2 ?
Merci pour vos retours.
Partager