简体   繁体   English

¿我如何从tidtcpclient和tidtcpserver发送和接收字符串并创建聊天?

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

im new at delphi languaje and im using Rad Studio to make apps work on every device with oune single programming. 即时通讯是delphi languaje的新功能,即时通讯使用Rad Studio通过单一编程即可使应用程序在每台设备上运行。 Right now Im supposed to make a chat using sockets, I made a chat for windows only using tclientsocket and tserversocket using the next code, what Im trying to do is make the exact thing but using tidtcpclient and tidtcpserver instead of tclientsocket and tserversocket 现在我应该使用套接字进行聊天,我只使用下一个代码使用tclientsocket和tserversocket针对Windows进行聊天,我试图做的是准确的事情,但是使用tidtcpclient和tidtcpserver而不是tclientsocket和tserversocket

Server: 服务器:

unit Server;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Win.ScktComp, Vcl.StdCtrls;

type
  TServidor = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    Button2: TButton;
    ServerSocket1: TServerSocket;
    Memo1: TMemo;
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure ServerSocket1ClientConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Servidor: TServidor;
  Str: String;

implementation

{$R *.dfm}

procedure TServidor.Button1Click(Sender: TObject);
var
  i: integer;
begin
     Str:=Edit1.Text;//Take the string (message) sent by the server
     Memo1.Text:=Memo1.Text+'yo: '+Str+#13#10;//Adds the message to the memo box
     Edit1.Text:='';//Clears the edit box
//Sends the messages to all clients connected to the server
     for i:=0 to ServerSocket1.Socket.ActiveConnections-1 do
      ServerSocket1.Socket.Connections[i].SendText(str);//Sent
end;

procedure TServidor.Button2Click(Sender: TObject);
begin
   if(ServerSocket1.Active = False)//The button caption is ‘Start’
   then
   begin
      ServerSocket1.Active := True;//Activates the server socket
      Memo1.Text:=Memo1.Text+'Servidor en linea'+#13#10;
      Button2.Caption:='Apagar';//Set the button caption
   end
   else//The button caption is ‘Stop’
   begin
      ServerSocket1.Active := False;//Stops the server socket
      Memo1.Text:=Memo1.Text+'Servidor fuera de linea'+#13#10;
      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.ServerSocket1ClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Socket.SendText('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
  Button1.Enabled:=true;
  Edit1.Enabled:=true;
end;

procedure TServidor.ServerSocket1ClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
Begin
//The server cannot send messages if there is no client connected to it
  if ServerSocket1.Socket.ActiveConnections-1=0 then
  begin
    Button1.Enabled:=false;
    Edit1.Enabled:=false;
  end;
end;

procedure TServidor.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
Begin
//Read the message received from the client and add it to the memo text
// The client identifier appears in front of the message
  Memo1.Text:=Memo1.Text+'Cliente'+IntToStr(Socket.SocketHandle)+' :'+Socket.ReceiveText+#13#10;
end;

end.

Client 客户

unit Server;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Win.ScktComp, Vcl.StdCtrls;

type
  TServidor = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    Button2: TButton;
    ServerSocket1: TServerSocket;
    Memo1: TMemo;
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure ServerSocket1ClientConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Servidor: TServidor;
  Str: String;

implementation

{$R *.dfm}

procedure TServidor.Button1Click(Sender: TObject);
var
  i: integer;
begin
     Str:=Edit1.Text;//Take the string (message) sent by the server
     Memo1.Text:=Memo1.Text+'yo: '+Str+#13#10;//Adds the message to the memo box
     Edit1.Text:='';//Clears the edit box
//Sends the messages to all clients connected to the server
     for i:=0 to ServerSocket1.Socket.ActiveConnections-1 do
      ServerSocket1.Socket.Connections[i].SendText(str);//Sent
end;

procedure TServidor.Button2Click(Sender: TObject);
begin
   if(ServerSocket1.Active = False)//The button caption is ‘Start’
   then
   begin
      ServerSocket1.Active := True;//Activates the server socket
      Memo1.Text:=Memo1.Text+'Servidor en linea'+#13#10;
      Button2.Caption:='Apagar';//Set the button caption
   end
   else//The button caption is ‘Stop’
   begin
      ServerSocket1.Active := False;//Stops the server socket
      Memo1.Text:=Memo1.Text+'Servidor fuera de linea'+#13#10;
      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.ServerSocket1ClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Socket.SendText('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
  Button1.Enabled:=true;
  Edit1.Enabled:=true;
end;

procedure TServidor.ServerSocket1ClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
Begin
//The server cannot send messages if there is no client connected to it
  if ServerSocket1.Socket.ActiveConnections-1=0 then
  begin
    Button1.Enabled:=false;
    Edit1.Enabled:=false;
  end;
end;

procedure TServidor.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
Begin
//Read the message received from the client and add it to the memo text
// The client identifier appears in front of the message
  Memo1.Text:=Memo1.Text+'Cliente'+IntToStr(Socket.SocketHandle)+' :'+Socket.ReceiveText+#13#10;
end;

end.

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. 特别是,在Button1Click()过程中向客户端广播消息。 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.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 Python3 的套接字聊天室中发送和接收,而不会在打字时中断客户端? - How can I send and recieve in a socket chat room in Python3 without the client being interrupted while typing? 需要将数据从TServersocket发送到TidTcpClient - Need to send data from TServersocket to TidTcpClient 如何通过套接字将字符串从线程发送到服务器 - How can I send strings from Threads to Server via Sockets 如何在 python 中同时接收/发送多条消息? (Python 多线程) - How can I recieve/send multiple messages at the same time in python? (Python Multithreading) 如何从一个套接字接收数据并将其发送到python中的另一个套接字? - How to recieve data from a one socket and send it to another socket in python? 如何使用Indy TIdTCPClient实例从Web服务器(包括响应主体)检索完整的HTTP响应? - How do I retrieve a complete HTTP response from a web server including response body using an Indy TIdTCPClient instance? c# 从 Stream 发送/接收图像 - c# Send/Recieve Image from Stream 如何禁止特定的套接字重新连接到我的聊天? - How can I ban a specific socket from reconnecting to my chat? 客户端不能接收从服务器发送的数据,而只能发送数据? - Client cannot recieve data sent from server but can send data only? 如何从客户端接收整数和字符串的缓冲区并正确存储它们? (cpp服务器,python客户端) - How to recieve a buffer of ints and strings from a client , and store them right? (cpp server , python client)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM