I spent some time to write a simple application to exchange data between TIdTCPServer
and TIdTCPClient
. But now I'm stuck.
I can send data from TIdTCPClient
to TIdTCPServer
and can process this.
But have no idea and official documentation didn't give any clue how to send data from TIdTCPServer
and process it on TIdTCPClient
. Please advise.
My code is simple:
main application:
var
Form1: TForm1;
implementation
uses ClientThread, ServerThread;
var
ClientThread: TClientThread;
ServerThread: TServerThread;
{$R *.fmx}
procedure TForm1.Button1Click(Sender: TObject);
var OutputDebugString:string;
begin
ServerThread:=TServerThread.Create(False);
ServerThread.Priority:=tpNormal;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
ClientThread:=TClientThread.Create(False);
ClientThread.Priority:=tpNormal;
end;
Server Thread:
unit ServerThread;
interface
uses
Classes, System.SysUtils, IdContext, IdTCPServer, TaskQue;
type
TServerThread = class(TThread) //MyThread - заданное нами имя потока.
private
{ Private declarations }
protected
procedure Execute; override;
end;
TServer = class(TObject)
IdTCPServer1: TIdTCPServer;
procedure IdTCPServer1Execute(AContext: TIdContext);
procedure IdTCPServer1Connect(AContext: TIdContext);
private
{ Private declarations }
constructor Create;
public
end;
type
TDatagram = record
Proto: byte;
Command: word;
DataSize: word;
data: array [0..4096] of byte;
end;
var
Server : TServer;
implementation
uses YouFreedom;
constructor TServer.Create;
begin
inherited Create;
IdTCPServer1 := TIdTCPServer.Create(nil);
IdTCPServer1.Bindings.Clear;
// IdTCPServer1.DefaultPort := 10001;
try
with idTCPserver1.Bindings.Add do
begin
IP := '127.0.0.1';
Port := 10001;
end;
finally //dirty hack
idTCPserver1.Bindings.Add.IP := '127.0.0.1';
idTCPserver1.Bindings.Add.Port := 10002;
end;
// idTCPserver1.Bindings.Add.Port:=10001;
// IdTCPServer1.Bindings.Add.IP := '127.0.0.1';
IdTCPServer1.Tag := 0;
IdTCPServer1.TerminateWaitTime := 5000;
IdTCPServer1.OnConnect := IdTCPServer1Connect;
IdTCPServer1.OnExecute := IdTCPServer1Execute;
end;
procedure TServer.IdTCPServer1Execute(AContext: TIdContext);
var
MIRec: TDatagram;
msRecInfo: TMemoryStream;
size: integer;
i:integer;
recieve:byte;
respstream: TMemoryStream;
begin
try
msRecInfo:= TMemoryStream.Create;
AContext.Connection.IOHandler.ReadStream(msRecInfo, -1, false);
msRecInfo.Position := 0;
msRecInfo.ReadBuffer(MIRec, msRecInfo.size);
Form1.addtoque := '1';
// Form1.s := inttostr(MIRec.Proto)
Form1.Memo1.Lines.Add('Proto = ' + inttostr(MIRec.Proto));
finally
msRecInfo.Free
end;
end;
procedure TServer.IdTCPServer1Connect(AContext: TIdContext);
begin
//AContext.Connection.Socket.WriteLn('hello');
end;
procedure TServerThread.Execute;
begin
Server := TServer.Create;
try
Server.IdTCPServer1.Active := True;
except
on E: Exception do
// OutputDebugString(PChar(E.ToString)); //do something
end;
end;
end.
Client thread:
unit ClientThread;
interface
uses
Classes, IdTCPClient;
type
TClientThread = class(TThread) //MyThread - заданное нами имя потока.
private
{ Private declarations }
protected
procedure Execute; override;
end;
TClient = class(TObject)
IdTCPClient1: TIdTCPClient;
// procedure IdTCPClient1OnWorkBegin(AContext: TIdContext);
private
{ Private declarations }
constructor Create;
public
end;
implementation
type
TDatagram = record
Proto: byte;
Command: word;
DataSize: word;
data: array [0..4096] of byte;
end;
var
ClientConnection : TClient;
constructor TClient.Create;
begin
inherited Create;
IdTCPClient1 := TIdTCPClient.Create(nil);
// IdTCPClient1.ReuseSocket := rsOSDependent;
IdTCPClient1.Host := '127.0.0.1';
IdTCPClient1.Port := 10001;
// IdTCPClient1.OnWorkBegin := IdTCPClient1OnWorkBegin;
end;
procedure TClientThread.Execute;
var
MIRec: TDatagram;
msRecInfo: TMemoryStream;
i,k:integer;
Client1: TIdTCPClient;
recieve:byte;
respstream: TMemoryStream;
begin
ClientConnection := TClient.Create;
ClientConnection.IdTCPClient1.Connect;
for k := 1 to 5 do begin
if ClientConnection.IdTCPClient1.Connected then begin
{ MIRec.DataSize := 64;
for i:=0 to MIRec.DataSize do
MIRec.data[i] := i;
for i:=129 to 4096 do MIRec.data[i] := 0;}
MIRec.Proto := 1;
MIRec.Command :=1;
try
msRecInfo := TMemoryStream.Create;
msRecInfo.WriteBuffer(MIRec, SizeOf(MIRec));
msRecInfo.Position := 0;
ClientConnection.IdTCPClient1.IOHandler.Write(msRecInfo, msRecInfo.Size, true);
finally
msRecInfo.Free;
end;
end;
end
end;
end.
You are misusing Bindings.Add()
and thus are creating 3 bindings:
127.0.0.1:10001
127.0.0.1:0
0.0.0.0:10002
I'm sure that is NOT what you really wanted.
As for your question - it depends on what your server needs to do.
If the server only responds to client commands then you can write a response directly in the OnExecute
event after reading a command. A client can read the response immediately after sending a command. This is the typical usage.
If the server only sends unsolicited data to clients, then you can Lock()
the server's Contexts
list when needed, locate the desired connection and write to it, then Unlock()
the list. A client will have to be reading asynchrously, such as in a thread, to read these messages.
If the server needs to do both , then this gets tricky. The best option is to implement a thread-safe outbound queue for each client, then you can put unsolicited data into the queue and have the OnExecute
send the contents of the queue when it is safe to do so.
I have posted examples of all these in the Embarcadero and Indy forums many times before. Search around.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.