Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TCP Client not receiving responses back from RTSP server

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:

  • http://effbot.org/zone/socket-intro.htm
  • http://www.ietf.org/rfc/rfc2326.txt
  • http://folk.uio.no/meccano/reflector/smallclient.html
  • http://www.samsungdforum.com/upload_files/files/guide/data/html/html_3/reference/rtsp_specification.html

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.

like image 336
Jerry Dodge Avatar asked Oct 14 '12 20:10

Jerry Dodge


2 Answers

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.
like image 191
whosrdaddy Avatar answered Nov 10 '22 07:11

whosrdaddy


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.

like image 41
Remy Lebeau Avatar answered Nov 10 '22 08:11

Remy Lebeau