¿How can I send and recieve strings from tidtcpclient and tidtcpserver and to create a chat?

前端 未结 1 499
忘掉有多难
忘掉有多难 2021-01-26 13:16

im new at delphi languaje and im using Rad Studio to make apps work on every device with oune single programming. Right now Im supposed to make a chat using sockets, I made a ch

相关标签:
1条回答
  • 2021-01-26 13:34

    A straight translation of the server code would look like this:

    unit Server;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdTCPServer, IdContext;
    
    type
      TServidor = class(TForm)
        Edit1: TEdit;
        Button1: TButton;
        Button2: TButton;
        IdTCPServer1: TIdTCPServer;
        Memo1: TMemo;
        procedure Button2Click(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure IdTCPServer1Connect(AContext: TIdContext);
        procedure IdTCPServer1Disconnect(AContext: TIdContext);
        procedure IdTCPServer1Execute(AContext: TIdContext);
      private
        { Private declarations }
        procedure UpdateButtons;
      public
        { Public declarations }
      end;
    
    var
      Servidor: TServidor;
    
    implementation
    
    {$R *.dfm}
    
    procedure TServidor.Button1Click(Sender: TObject);
    var
      i: integer;
      list: TIdContextList;
      Str: String;
    begin
      Str := Edit1.Text;//Take the string (message) sent by the server
      Memo1.Lines.Add('yo: ' + Str); //Adds the message to the memo box
      Edit1.Text := '';//Clears the edit box
      //Sends the messages to all clients connected to the server
      list := IdTCPServer1.Contexts.LockList;
      try
        for i := 0 to list.Count-1 do
        begin
          try
            TIdContext(list[i]).Connection.IOHandler.WriteLn(str);//Sent
          except 
          end;
        end;
      finally
        IdTCPServer1.Contexts.UnlockList;
      end;
    end;
    
    procedure TServidor.Button2Click(Sender: TObject);
    begin
      if not IdTCPServer1.Active //The button caption is ‘Start’
      then
      begin
        IdTCPServer1.Active := True;//Activates the server socket
        Memo1.Lines.Add('Servidor en linea');
        Button2.Caption := 'Apagar';//Set the button caption
      end
      else//The button caption is ‘Stop’
      begin
        IdTCPServer1.Active := False;//Stops the server socket
        Memo1.Lines.Add('Servidor fuera de linea');
        Button2.Caption := 'Encender';
        //If the server is closed, then it cannot send any messages
        Button1.Enabled := false;//Disables the “Send” button
        Edit1.Enabled := false;//Disables the edit box
      end;
    end;
    
    procedure TServidor.UpdateButtons;
    var
      list: TIdContextList;
    begin
      list := IdTCPServer1.Contexts.LockList;
      try
        Button1.Enabled := list.Count > 0;
        Edit1.Enabled := Button1.Enabled;
      finally
        IdTCPServer1.Contexts.UnlockList;
      end;
    end;
    
    procedure TServidor.IdTCPServer1Connect(AContext: TIdContext);
    begin
      AContext.Connection.IOHandler.WriteLn('Conectado');//Sends a message to the client
      //If at least a client is connected to the server, then the server can communicate
      //Enables the Send button and the edit box
      TThread.Queue(nil, UpdateButtons);
    end;
    
    procedure TServidor.IdTCPServer1Disconnect(AContext: TIdContext);
    begin
      //The server cannot send messages if there is no client connected to it
      TThread.Queue(nil, UpdateButtons);
    end;
    
    procedure TServidor.IdTCPServer1Execute(AContext: TIdContext);
    var
      Str: String;
    begin
      //Read the message received from the client and add it to the memo text
      // The client identifier appears in front of the message
      Str := 'Cliente '+ AContext.Binding.PeerIP + ' :' + AContext.Connection.IOHandler.ReadLn;
      TThread.Queue(nil,
        procedure
        begin
          Memo1.Lines.Add(Str);
        end
      );
    end;
    
    end.
    

    This is not the safest way to implement a server, though. In particular, broadcasting messages to client in the Button1Click() procedure. A safer approach would look more like this instead:

    unit Server;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdTCPServer, IdContext;
    
    type
      TServidor = class(TForm)
        Edit1: TEdit;
        Button1: TButton;
        Button2: TButton;
        IdTCPServer1: TIdTCPServer;
        Memo1: TMemo;
        procedure FormCreate(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure IdTCPServer1Connect(AContext: TIdContext);
        procedure IdTCPServer1Disconnect(AContext: TIdContext);
        procedure IdTCPServer1Execute(AContext: TIdContext);
      private
        { Private declarations }
        procedure UpdateButtons;
      public
        { Public declarations }
      end;
    
    var
      Servidor: TServidor;
    
    implementation
    
    {$R *.dfm}
    
    uses
      IdTCPConnection, IdYarn, IdThreadSafe;
    
    type
      TMyContext = class(TIdServerContext)
      private
        Queue: TIdThreadSafeStringList;
        QueuePending: Boolean;
      public
        constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil); override;
        destructor Destroy; override;
        procedure AddToQueue(const s: string);
        procedure SendQueue;
      end;
    
    constructor TMyContext.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil);
    begin
      inherited;
      Queue := TIdThreadSafeStringList.Create;
    end;
    
    destructor TMyContext.Destroy;
    begin
      Queue.Free;
      inherited;
    end;
    
    procedure TMyContext.AddToQueue(const s: string);
    var
      list: TStringList;
    begin
      list := Queue.Lock;
      try
        list.Add(s);
        QueuePending := True;
      finally
        Queue.Unlock;
      end;
    end;
    
    procedure TMyContext.SendQueue;
    var
      list: TStringList;
      tmpList: TStringList;
      i: Integer;
    begin
      if not QueuePending then Exit;
      tmp := nil;
      try
        list := Queue.Lock;
        try
          if list.Count = 0 then
          begin
            QueuePending := False;
            Exit;
          end;
          tmpList := TStringList.Create;
          tmpList.Assign(list);
          list.Clear;
          QueuePending := False;
        finally
          Queue.Unlock;
        end;
        for i := 0 to tmpList.Count-1 do
          Connection.IOHandler.WriteLn(tmpList[i]);
      finally
        tmpList.Free;
      end;
    end;
    
    procedure TServidor.FormCreate(Sender: TObject);
    begin
      IdTCPServer1.ContextClass := TMyContext;
    end;
    
    procedure TServidor.Button1Click(Sender: TObject);
    var
      i: integer;
      list: TIdContextList;
      Str: String;
    begin
      Str := Edit1.Text;//Take the string (message) sent by the server
      Memo1.Lines.Add('yo: ' + Str); //Adds the message to the memo box
      Edit1.Text := '';//Clears the edit box
      //Sends the messages to all clients connected to the server
      list := IdTCPServer1.Contexts.LockList;
      try
        for i := 0 to list.Count-1 do
          TMyContext(list[i]).AddToQueue(str);//Sent
      finally
        IdTCPServer1.Contexts.UnlockList;
      end;
    end;
    
    procedure TServidor.Button2Click(Sender: TObject);
    begin
      if not IdTCPServer1.Active //The button caption is ‘Start’
      then
      begin
        IdTCPServer1.Active := True;//Activates the server socket
        Memo1.Lines.Add('Servidor en linea');
        Button2.Caption := 'Apagar';//Set the button caption
      end
      else//The button caption is ‘Stop’
      begin
        IdTCPServer1.Active := False;//Stops the server socket
        Memo1.Lines.Add('Servidor fuera de linea');
        Button2.Caption := 'Encender';
        //If the server is closed, then it cannot send any messages
        Button1.Enabled := false;//Disables the “Send” button
        Edit1.Enabled := false;//Disables the edit box
      end;
    end;
    
    procedure TServidor.UpdateButtons;
    var
      list: TIdContextList;
    begin
      list := IdTCPServer1.Contexts.LockList;
      try
        Button1.Enabled := list.Count > 0;
        Edit1.Enabled := Button1.Enabled;
      finally
        IdTCPServer1.Contexts.UnlockList;
      end;
    end;
    
    procedure TServidor.IdTCPServer1Connect(AContext: TIdContext);
    begin
      AContext.Connection.IOHandler.WriteLn('Conectado');//Sends a message to the client
      //If at least a client is connected to the server, then the server can communicate
      //Enables the Send button and the edit box
      TThread.Queue(nil, UpdateButtons);
    end;
    
    procedure TServidor.IdTCPServer1Disconnect(AContext: TIdContext);
    begin
      //The server cannot send messages if there is no client connected to it
      TThread.Queue(nil, UpdateButtons);
    end;
    
    procedure TServidor.IdTCPServer1Execute(AContext: TIdContext);
    var
      LContext: TMyContext;
      Str: String;
    begin
      LContext := TMyContext(AContext);
    
      //send pending messages from the server
      LContext.SendQueue;
    
      //check for a message received from the client
      if AContext.IOHandler.InputBufferIsEmpty then
      begin
        AContext.IOHandler.CheckForDataOnSource(100);
        AContext.IOHandler.CheckForDisconnect;
        if AContext.IOHandler.InputBufferIsEmpty then Exit;
      end;
    
      //read the message received from the client and add it to the memo text
      // The client identifier appears in front of the message
      Str := 'Cliente '+ AContext.Binding.PeerIP + ' :' + AContext.Connection.IOHandler.ReadLn;
      TThread.Queue(nil,
        procedure
        begin
          Memo1.Lines.Add(Str);
        end
      );
    end;
    
    end.
    

    As for the client, you did not show your client code (you showed your server code twice), but here is what a client implementation could look like (note that this is not the best way to implement a client that can receive unsolicited server messages, though):

    unit Client;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdTCPClient;
    
    type
      TCliente = class(TForm)
        Edit1: TEdit;
        Button1: TButton;
        Button2: TButton;
        IdTCPClient1: TIdTCPClient;
        Memo1: TMemo;
        Timer1: TTimer;
        procedure Button2Click(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
      private
        { Private declarations }
        procedure CloseClient;
      public
        { Public declarations }
      end;
    
    var
      Cliente: TCliente;
    
    implementation
    
    {$R *.dfm}
    
    procedure TCliente.Button1Click(Sender: TObject);
    var
      i: integer;
      Str: String;
    begin
      Str := Edit1.Text;//Take the string (message) sent by the client
      Memo1.Lines.Add('yo: '+Str);//Adds the message to the memo box
      Edit1.Text := '';//Clears the edit box
      //Sends the message to the server
      try
        IdTCPClient1.IOHandler.WriteLn(str);//Sent
      except
        CloseClient;
      end;
    end;
    
    procedure TServidor.Button2Click(Sender: TObject);
    begin
      if not IdTCPClient1.Connected //The button caption is ‘Start’
      then
      begin
        IdTCPClient1.Connect;//Activates the client socket
        Memo1.Lines.Add('Cliente en linea');
        Button2.Caption := 'Apagar';//Set the button caption
        //Enables the Send button and the edit box
        Button1.Enabled := true;
        Edit1.Enabled := true;
        Timer1.Enabled := True;
      end
      else//The button caption is ‘Stop’
      begin
        CloseClient;
      end;
    end;
    
    procedure TCliente.CloseClient;
    begin
      IdTCPClient1.Disconnect;//Stops the client socket
      Memo1.Lines.Add('Cliente fuera de linea');
      Button2.Caption := 'Encender';
      //If the client is closed, then it cannot send any messages
      Button1.Enabled := false;//Disables the “Send” button
      Edit1.Enabled := false;//Disables the edit box
      Timer1.Enabled := false;
    end;
    
    procedure TCliente.Timer1Timer(Sender: TObject);
    begin
      try
        //check for a message from the server
        if IdTCPClient1.IOHandler.InputBufferIsEmpty then
        begin
          IdTCPClient1.IOHandler.CheckForDataOnSource(10);
          IdTCPClient1.IOHandler.CheckForDisconnect;
          if IdTCPClient1.IOHandler.InputBufferIsEmpty then Exit;
        end;
        //Read the message received from the server and add it to the memo text
        // The client identifier appears in front of the message
        Memo1.Lines.Add('Servidor :' + IdTCPClient1.IOHandler.ReadLn);
      except
        CloseClient;
      end;
    end;
    
    end.
    
    0 讨论(0)
提交回复
热议问题