In Delphi XE2, I'm using the TTCPClient
component to communicate with an RTSP server. After trial and error not getting a response back from the server, I switched the project to send HTTP requests via port 80 (instead of 554 for RTSP) and tried to send a request to a website (www.google.com specifically). I'm still not getting any response.
I have a TTCPClient
component on the main form (Form1
) called Client
, a TMemo
control called Log
, a TEdit
control called txtHost
, and a TBitBtn
control. Here's the relevant parts of the code:
Connecting to Server
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
if Client.Active then Client.Disconnect;
Client.RemoteHost:= txtHost.Text;
Client.RemotePort:= '80'; // '554';
Client.Connect;
end;
OnConnect Event Handler (HTTP)
procedure TForm1.ClientConnect(Sender: TObject);
var
S: String;
begin
Client.Sendln('GET / HTTP/1.0');
Client.SendLn('');
end;
OnConnect Event Handler (RTSP)
procedure TForm1.ClientConnect(Sender: TObject);
var
S: String;
begin
Client.SendLn('OPTIONS * RTSP/1.0');
Client.SendLn('CSeq:0');
Client.SendLn('');
end;
OnReceive Event Handler
procedure TForm1.ClientReceive(Sender: TObject; Buf: PAnsiChar;
var DataLen: Integer);
var
S, R: String;
begin
S:= Client.Receiveln;
while S <> '' do begin
R:= R+ S;
S:= Client.Receiveln;
end;
Log.Lines.Append('> RECEIVED ' + R);
end;
OnError Event Handler
procedure TForm1.ClientError(Sender: TObject; SocketError: Integer);
begin
Log.Lines.Append('> ERROR '+IntToStr(SocketError));
end;
The OnReceive
event is never called, nothing is coming back from any Server I'm connecting to.
What am I doing wrong here?
References
These are some links which I'm referencing to:
The camera I'm working with is Grandstream GXV3601LL
UPDATE
I've concluded that the issue is with the RTSP server, and have asked a question on the forums on Grandstream's website. The code does work with other server connections.
This works for me, it depends if you are in blocking mode or not:
unit Unit11;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Sockets, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, StdCtrls;
type
TForm1 = class(TForm)
IdTCPClient1: TIdTCPClient;
TcpClient1: TTcpClient;
Memo1: TMemo;
procedure TcpClient1Connect(Sender: TObject);
procedure TcpClient1Receive(Sender: TObject; Buf: PAnsiChar; var DataLen: Integer);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
TcpClient1.BlockMode := bmBlocking;
TcpClient1.RemoteHost := 'www.google.com';
TcpClient1.RemotePort := '80';
TcpClient1.Connect;
end;
procedure TForm1.TcpClient1Connect(Sender: TObject);
var s : string;
begin
memo1.Lines.Add('connected');
TcpClient1.Sendln('GET /');
s := TcpClient1.Receiveln;
memo1.Lines.Add(S);
end;
end.
EDIT
here is a real world example with a RTSP server (youtube in this case) I used Indy IdTcpClient
unit Unit11;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Sockets, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Client: TIdTCPClient;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var s : string;
begin
Client.Host := 'v5.cache6.c.youtube.com';
Client.Port := 554;
Client.Connect;
Client.IOHandler.Writeln('OPTIONS * RTSP/1.0');
Client.IOHandler.Writeln('CSeq: 1');
Client.IOHandler.Writeln('');
s := Client.IOHandler.ReadLn;
Memo1.Lines.Add(s);
s := Client.IOHandler.ReadLn;
Memo1.Lines.Add(s);
end;
end.
The reason the OnReceive
event is not called is because TTCPClient
is NOT an asynchronous component, like you are trying to treat it. The OnReceive
event DOES NOT work the same way as the old TClientSocket.OnRead
event. The OnReceive
event is called inside of the ReceiveBuf()
method only (ReceiveLn()
calls ReceiveBuf()
internally). The data that is passed to the OnReceive
event is the same data that the ReceiveBuf()
method returns on output. You have a catch-22 situation - you are waiting for the OnReceive
event before calling ReceiveLn()
, but OnReceive
will not be triggered until you call ReceiveLn()
first. If you want to use TTCPClient
asynchronously, you will have to call its ReceiveLn()
method periodically, either in a timer or worker thread, NOT inside the OnReceive
event.
The TTCPClient
component is part of the old CLX framework for Kylix. It is not part of the VCL, or even FireMonkey, and should not be used anymore. Either use the old TClientSocket
component (which is deprecated but still available), or change to another component library, such as Indy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With