Ir al contenido


Foto

Aplicacion Cliente/servidor con Indy 10.5.7 Problema para desconectar cliente


  • Por favor identifícate para responder
No hay respuestas en este tema

#1 genyus00

genyus00

    Advanced Member

  • Miembros
  • PipPipPip
  • 52 mensajes
  • LocationBogota

Escrito 10 abril 2011 - 04:37

Hola, buenas a todos, este es el primer tema que abro. a  ver como me va. La cuestion es la siguiente, actualmente trabajo con delphi XE y la version indy 10.5.7, anteriorme en delphi 7 cpon los indy 9.xxxx habia creado una aplicacion cliente servidor con componentes TidTCPClient y TidTCPServer enviando los mensajes como un objeto de tipo "Record" el cual encapsula los parametros que deseo enviar de un cliente a un servidor y viceversa, dado que me funcionaba sin problema, decidi traermelo a delphi XE, encontre varios problemas por que algunas propiedades de los componentes cambiaron de nombre y de forma de manejo , pero alli lo hice funcionar, mi sorpresa actual es que si envio un mensaje al servidor y luego le doy al boton desconectar en el cliente, se obtiene el mensaje en servidor y cliente que la conexion se cerro (esto es correcto), pero en realidad en el cliente la conexion sigue activa, y no encuentro como cerrar, ni por las buenas ni por las malas, adicionalmente recibo en el cliente el mensaje "su conexion se a cerrado graciosamente" "conection closedgracefully", mirando en muchos foros y hasta en al pagina de indy, la explicacion que dan es que al cerrar el cliente el servidor pareciera no enterarse, pero la cosa es que si se entera, por que muestra en el log del server que evidentemente un cliente se deconecto, por otro lado que cambia en la accion de enviar mensaje que haga que despues la coneccion del cliente no se pueda cerrar, dado que si activo el cliente y no envio mensaje y le doy dessconectar funciona bien, puedo darle conectar/desconectar cuantas veces quiera que no se bloquea, pero al enviar el mensaje y querer cerrar el cliente pailas... no se permite desactivar el TidTCPclient. el codigo de la aplicacion en el siguiente.. cualquie ayuda en el analis se los agradezco.  :cry: :grin: :sad: 

CODIGO DEL CLIENTE


delphi
  1. unit ClientFrmMainUnit;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, StdCtrls,
  8.   GlobalUnit, IdAntiFreezeBase, IdAntiFreeze,idglobal;
  9.  
  10. type
  11.   TClientFrmMain = class(TForm)
  12.   IncomingMessages: TMemo;
  13.   Label1: TLabel;
  14.  
  15.   IdTCPClient1: TIdTCPClient;
  16.   Label2: TLabel;
  17.   EditCommand: TComboBox;
  18.   Label3: TLabel;
  19.   EditMessage: TEdit;
  20.   Label4: TLabel;
  21.   EditRecipient: TEdit;
  22.   ButtonSend: TButton;
  23.   puertoremoto: TEdit;
  24.   ipremota: TEdit;
  25.   btndesconectar: TButton;
  26.   lbl4: TLabel;
  27.   lbl3: TLabel;
  28.   IdAntiFreeze1: TIdAntiFreeze;
  29.   btnconectar: TButton;
  30.  
  31.   procedure ButtonSendClick(Sender: TObject);
  32.   procedure btnconectarClick(Sender: TObject);
  33.   procedure btndesconectarClick(Sender: TObject);
  34.   procedure IdTCPClient1Connected(Sender: TObject);
  35.   procedure IdTCPClient1Disconnected(Sender: TObject);
  36.  
  37.   private
  38.         procedure Log(s: string);
  39.         public
  40.         end;
  41.  
  42.   TClientHandleThread = class(TThread)
  43.   private
  44.         CB: TCommBlock;
  45.         procedure HandleInput;
  46.         protected
  47.         procedure Execute; override;
  48.         end;
  49. var
  50.   ClientFrmMain: TClientFrmMain;
  51.   ClientHandleThread: TClientHandleThread;
  52.  
  53. implementation
  54.  
  55. {$R *.DFM}
  56. procedure TClientFrmMain.Log(s: string);
  57. begin
  58. IncomingMessages.Lines.Add(DateTimeToStr(now) + ' ' + s);
  59. end;
  60.  
  61. procedure TClientHandleThread.HandleInput;
  62. begin
  63. if CB.Command = 'MESSAGE' then
  64.   ClientFrmMain.IncomingMessages.Lines.Add (CB.UsuarioNom + ': ' + CB.Msj)
  65. else
  66. if CB.Command = 'DIALOG' then
  67.   MessageDlg ('"'+CB.UsuarioNom+'" sends you this message:'+#13+CB.Msj, mtInformation, [mbOk], 0)
  68. else
  69.   MessageDlg('Unknown command "'+CB.Command+'" containing this message:'+#13+CB.Msj, mtError, [mbOk], 0);
  70. end;
  71.  
  72. procedure TClientHandleThread.Execute;
  73. var RxBuf:TIdBytes;
  74. begin
  75. ClientFrmMain.IdTCPClient1.ReadTimeout := 1000;
  76. repeat
  77.     try
  78.         ClientFrmMain.IdTCPClient1.IOHandler.ReadBytes(RxBuf, SizeOf (CB));
  79.         Idglobal.BytesToRaw(RxBuf, CB, SizeOf (CB));
  80.         Synchronize(HandleInput);
  81.         except
  82.             // nothing
  83.         end;
  84.     until (Terminated) or (not ClientFrmMain.IdTCPClient1.Connected);
  85. Free;
  86. end;
  87.  
  88. procedure TClientFrmMain.IdTCPClient1Connected(Sender: TObject);
  89. begin
  90. Log('Conectado al Servidor ' + ipremota.text + ':' + puertoremoto.text);
  91. end;
  92.  
  93. procedure TClientFrmMain.IdTCPClient1Disconnected(Sender: TObject);
  94. begin
  95. Log('Desconectado del Servidor' + ipremota.text + ':' + puertoremoto.text);
  96. end;
  97.  
  98. procedure TClientFrmMain.btnconectarClick(Sender: TObject);
  99. begin
  100. try
  101.   IdTCPClient1.Host := IPRemota.text;
  102.   IdTCPClient1.Port := StrToInt(PuertoRemoto.text);
  103.   try
  104.     IdTCPClient1.Connect;
  105.     ClientHandleThread := TClientHandleThread.Create(True);
  106.     ClientHandleThread.FreeOnTerminate:=True;
  107.     ClientHandleThread.Resume;
  108.     ButtonSend.Enabled := IdTCPClient1.Connected;
  109.     btnconectar.Enabled:=not IdTCPClient1.Connected;
  110.     btndesconectar.Enabled:=IdTCPClient1.Connected;
  111.     except
  112.         on E: Exception do MessageDlg ('Error while connecting:'+#13+E.Message, mtError, [mbOk], 0);
  113.         end;
  114.   except
  115.         raise exception.Create('Error');
  116.   end;
  117. end;
  118.  
  119. procedure TClientFrmMain.btndesconectarClick(Sender: TObject);
  120. begin
  121. try
  122.   if IdTCPClient1.Connected then
  123.     begin
  124.     ClientHandleThread.Terminate;
  125.     IdTCPClient1.Disconnect;
  126.     ButtonSend.Enabled := IdTCPClient1.Connected;
  127.     btnconectar.Enabled:=not IdTCPClient1.Connected;
  128.     btndesconectar.Enabled:=IdTCPClient1.Connected;
  129.     end;
  130. except
  131.     on E: Exception do
  132.         showmessage(E.Message);
  133.     end;
  134. end;
  135.  
  136. procedure TClientFrmMain.ButtonSendClick(Sender: TObject);
  137. var
  138.   CommBlock : TCommBlock;
  139.   RxBuf:TIdBytes;
  140. begin
  141.   CommBlock.Command      := EditCommand.Text;
  142.   CommBlock.UsuarioNom  := 'PC0117';//DNS
  143.   CommBlock.Msj          := EditMessage.Text;
  144.   CommBlock.Hora        := FormatDateTime('HH:mm:ss',Time);
  145.   CommBlock.ResiveName := EditRecipient.Text;
  146.   CommBlock.Turno        := '';
  147.   CommBlock.Modulo      := '';
  148.   RxBuf := Idglobal.RawToBytes(CommBlock, SizeOf (CommBlock));
  149.   IdTCPClient1.IOHandler.Write(RxBuf);// and there it goes...
  150. end;
  151.  
  152. end.



CODIGO DEL SERVIDOR


delphi
  1. unit ServerFrmMainUnit;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   StdCtrls, IdTCPServer, Idcontext,IdBaseComponent,idglobal,
  8.   IdComponent, IdStack, IdCustomTCPServer,IdSocketHandle;
  9.  
  10. type
  11.   PClient  = ^TClient;
  12.   TClient  = record  // Object holding data of client (see events)
  13.               IPAddress ,  // Guarda el IP de cada cliente
  14.               DNS        : String[20]; { Hostname }
  15.               Connected,                          { Time of connect }
  16.               LastAction  : TDateTime;            { Time of last transaction }
  17.               Context    : Pointer;              { Pointer to thread }
  18.               end;
  19.  
  20.   TServerFrmMain = class(TForm)
  21.   IdTCPServer1: TIdTCPServer;
  22.   CBServerActive: TCheckBox;
  23.   Protocol: TMemo;
  24.   DefaultServerPort: TEdit;
  25.   btn1: TButton;
  26.   DefaultServerIP: TEdit;
  27.   lbl2: TLabel;
  28.   lbl1: TLabel;
  29.  
  30.   procedure CBServerActiveClick(Sender: TObject);
  31.   procedure IdTCPServer1Connect(AContext: TIdContext);
  32.   procedure IdTCPServer1Execute(AContext: TIdContext);
  33.   procedure IdTCPServer1Disconnect(AContext: TIdContext);
  34.   procedure FormCreate(Sender: TObject);
  35.   procedure FormClose(Sender: TObject; var Action: TCloseAction);
  36.   procedure btn1Click(Sender: TObject);
  37.   procedure IdTCPServer1Status(ASender: TObject; const AStatus: TIdStatus;
  38.   const AStatusText: string);
  39.  
  40.   private
  41.         procedure Log(s: string);
  42.   Public
  43.       end;
  44.  
  45. var
  46.   ServerFrmMain  : TServerFrmMain;
  47.   Clients        : TThreadList;    // Holds the data of all clients
  48.   log:string;
  49.  
  50. implementation
  51.  
  52. uses GlobalUnit;
  53.  
  54. {$R *.DFM}
  55. procedure TServerFrmMain.Log(s: string);
  56. begin
  57. protocol.Lines.Add(DateTimeToStr(now) + ' ' + s);
  58. end;
  59.  
  60. procedure TServerFrmMain.btn1Click(Sender: TObject);
  61. var Bindings: TIdSocketHandles;
  62. begin
  63. Bindings := TIdSocketHandles.Create(IdTCPServer1);
  64. try
  65.   with Bindings.Add do
  66.         begin
  67.         IP := DefaultServerIP.text;
  68.         Port := StrToInt(DefaultServerPort.text);
  69.         end;
  70.   try
  71.       IdTCPServer1.Bindings := Bindings;
  72.       IdTCPServer1.Active := True;
  73.       Log('Server Iniciado en ' + DefaultServerIP.text);
  74.       Log('Esperando comunicación cliente...');
  75.       except on E: Exception do
  76.             ShowMessage(E.Message);
  77.       end;
  78.   finally
  79.         Bindings.Free;
  80.   end;
  81. end;
  82.  
  83. procedure TServerFrmMain.CBServerActiveClick(Sender: TObject);
  84. begin
  85. IdTCPServer1.Active := CBServerActive.Checked;
  86. end;
  87.  
  88. procedure TServerFrmMain.IdTCPServer1Connect(AContext: TIdContext);
  89. var NewClient: PClient;
  90. begin
  91. GetMem(NewClient, SizeOf(TClient));
  92. NewClient.IPAddress := AContext.Connection.Socket.Binding.PeerIP;
  93. NewClient.DNS := GStack.HostByAddress(NewClient.IPAddress);
  94. NewClient.Connected  := Now;
  95. NewClient.LastAction  := NewClient.Connected;
  96. NewClient.Context    :=AContext;
  97. AContext.Data:=TObject(NewClient);
  98.  
  99. try
  100.   Clients.LockList.Add(NewClient);
  101.   finally
  102.         Clients.UnlockList;
  103.   end;
  104.  
  105. Protocol.Lines.Add(TimeToStr(Time)+' Connection from "'+NewClient.DNS+'"');
  106. Log('Connectado a : ' + AContext.Binding.PeerIP + ':' + IntToStr(AContext.Binding.Port));
  107. end;
  108.  
  109. procedure TServerFrmMain.IdTCPServer1Execute(AContext: TIdContext);
  110. var ActClient, RecClient: PClient;
  111. Paquete, NewPaquete: TCommBlock;
  112. RecContext: TIdContext;
  113. i: Integer;
  114. RxBuf:TIdBytes;
  115. begin
  116. if AContext.Connection.Connected then    //not AContext.Terminated and
  117.   begin
  118.   AContext.Connection.IOHandler.readBytes(RxBuf, SizeOf (Paquete));
  119.   Idglobal.BytesToRaw(RxBuf, Paquete, SizeOf (Paquete));// Obtener el texto enviado desde el cliente
  120.   ActClient := PClient(AContext.Data);
  121.   ActClient.LastAction := Now;  // update the time of last actio
  122.  
  123.   if (Paquete.Command = 'MESSAGE') or (Paquete.Command = 'DIALOG') then
  124.       begin  // 'MESSAGE': A message was send - forward or broadcast it
  125.           // 'DIALOG':  A dialog-window shall popup on the recipient's screen
  126.           // it's the same code for both commands...
  127.  
  128.       if Paquete.ResiveName = '' then
  129.           begin  // no recipient given - broadcast
  130.           Protocol.Lines.Add (TimeToStr(Time)+' Broadcasting '+Paquete.Command+': "'+Paquete.Msj+'"');
  131.           NewPaquete := Paquete;  // nothing to change ;-))
  132.  
  133.           with Clients.LockList do
  134.               try
  135.                 for i := 0 to Count-1 do  // iterate through client-list
  136.                   begin
  137.                     RecClient := Items[i];          // get client-object
  138.                     RecContext := RecClient.Context; // conseguir el hilo del cliente
  139.                     RxBuf := Idglobal.RawToBytes(RecContext, SizeOf (RecContext));
  140.                     AContext.Connection.IOHandler.Write(RxBuf);// enviar el material
  141.                     AContext.Connection.IOHandler.WriteBufferFlush;
  142.                     AContext.Connection.IOHandler.WriteBufferClose;
  143.                     end;
  144.               finally
  145.                     Clients.UnlockList;
  146.               end;
  147.           end
  148.       else
  149.           begin  // receiver given - search him and send it to him
  150.           NewPaquete := Paquete; // again: nothing to change ;-))
  151.           Protocol.Lines.Add(TimeToStr(Time)+' Sending '+Paquete.Command+' to "'+Paquete.ResiveName+'": "'+Paquete.Msj+'"');
  152.           with Clients.LockList do
  153.               try
  154.                   for i := 0 to Count-1 do
  155.                       begin
  156.                       RecClient:=Items[i];
  157.                       if RecClient.DNS=Paquete.ResiveName then  // we don't have a login function so we have to use the DNS (Hostname)
  158.                         begin
  159.                         RecContext:=RecClient.Context;
  160.                         RxBuf := Idglobal.RawToBytes(RecContext, SizeOf (RecContext));
  161.                         AContext.Connection.IOHandler.Write(RxBuf);// enviar el material
  162.                         AContext.Connection.IOHandler.WriteBufferFlush;
  163.                         AContext.Connection.IOHandler.WriteBufferClose;
  164.                         end;
  165.                       end;
  166.               finally
  167.                       Clients.UnlockList;
  168.                       end;
  169.           end;
  170.       end
  171.   else
  172.       begin  // unknown command given
  173.       Protocol.Lines.Add (TimeToStr(Time)+' Unknown command from "'+Paquete.UsuarioNom+'": '+Paquete.Command);
  174.       NewPaquete.Command := 'DIALOG';      // the message should popup on the client's screen
  175.       NewPaquete.UsuarioNom := '[Server]';  // the server's username
  176.       NewPaquete.Msj := 'I don''t understand your command: "'+Paquete.Command+'"';  // the message to show
  177.       NewPaquete.ResiveName := '[return-to-sender]'; // unnecessary
  178.       RxBuf := Idglobal.RawToBytes(NewPaquete, SizeOf (NewPaquete));
  179.       AContext.Connection.IOHandler.Write(RxBuf);// y ahí va ...
  180.       end;
  181.  
  182.   AContext.Connection.IOHandler.WriteBufferFlush;
  183.   AContext.Connection.IOHandler.WriteBufferClose;
  184.   end;
  185. end;
  186.  
  187. procedure TServerFrmMain.IdTCPServer1Status(ASender: TObject;
  188.   const AStatus: TIdStatus; const AStatusText: string);
  189. begin
  190. protocol.Lines.Add('Status : ' + AStatusText);
  191. end;
  192.  
  193. procedure TServerFrmMain.IdTCPServer1Disconnect(AContext: TIdContext);
  194. var ActClient: PClient;
  195. begin
  196. ActClient := PClient(AContext.Data);
  197. Protocol.Lines.Add (TimeToStr(Time)+' Disconnect from "'+ActClient^.DNS+'"');
  198. Log('Desconectado de : ' + AContext.Binding.PeerIP + ':' + IntToStr(AContext.Binding.Port));
  199.  
  200. try
  201.   Clients.LockList.Remove(ActClient);
  202.   finally
  203.         Clients.UnlockList;
  204.   end;
  205.  
  206. FreeMem(ActClient);
  207. AContext.Data := nil;
  208. end;
  209.  
  210. procedure TServerFrmMain.FormCreate(Sender: TObject);
  211. begin
  212. Clients := TThreadList.Create;
  213. end;
  214.  
  215. procedure TServerFrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
  216. begin
  217. IdTCPServer1.Active := False;
  218. Clients.Free;
  219. end;
  220.  
  221. end.



UNIDAD COMUN A LOS DOS PROYECTOS


delphi
  1. unit GlobalUnit;
  2.  
  3. interface
  4. type
  5. TCommBlock = record // the Communication Block used in both parts (Server+Client)
  6.             Command, //comando a interpretar por el usuario
  7.             UsuarioNom,//usuario que envio el mensage
  8.             Msj,//mensage enviado por el usuario
  9.             Hora,
  10.             ResiveName, //name of receiver
  11.             Turno,//tabla en la que se realizo la operacion
  12.             Modulo:string[100]; //codigo o pk del registro modificado o registrado
  13.             end;
  14.  
  15.  
  16. implementation
  17.  
  18. end.

  :( :| : 8o|
  • 0




IP.Board spam blocked by CleanTalk.