6

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.

Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327

2 Answers2

6

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.
whosrdaddy
  • 11,720
  • 4
  • 50
  • 99
  • Hmm, it does work for me using your example, but when I put the IP of the RTSP camera it fails with socket error 10053 – Jerry Dodge Oct 14 '12 at 21:51
  • error 10053 is WSAECONNABORTED, so it seems that the camera is not allowing your connection. What brand of camera are we talking about here? – whosrdaddy Oct 14 '12 at 21:58
  • I've also verified all the camera's settings, including one to allow anonymous unauthenticated viewing – Jerry Dodge Oct 14 '12 at 22:01
  • it should be doable, you just need to include an authorization element. Look at this page for pointers :http://forum.videolan.org/viewtopic.php?f=13&t=44780 – whosrdaddy Oct 14 '12 at 22:11
  • I guess I'll have to accept your answer since it does really answer the question, yet I still have an issue of these particular cameras not responding. I've posted a question in Grandstream's forums on this. – Jerry Dodge Oct 14 '12 at 23:14
2

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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770