【问题标题】:TCP Client not receiving responses back from RTSP serverTCP 客户端未收到来自 RTSP 服务器的响应
【发布时间】:2012-10-16 05:28:48
【问题描述】:

在 Delphi XE2 中,我使用 TTCPClient 组件与 RTSP 服务器进行通信。经过反复试验,没有从服务器得到响应,我将项目切换为通过端口 80(而不是 RTSP 的 554)发送 HTTP 请求,并尝试向网站(特别是 www.google.com)发送请求。我仍然没有得到任何回应。

我在主窗体 (Form1) 上有一个名为ClientTTCPClient 组件、一个名为LogTMemo 控件、一个名为txtHostTEdit 控件和一个TBitBtn 控件.以下是代码的相关部分:

连接到服务器

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  if Client.Active then Client.Disconnect;
  Client.RemoteHost:= txtHost.Text;
  Client.RemotePort:= '80'; // '554';
  Client.Connect;
end;

OnConnect 事件处理程序 (HTTP)

procedure TForm1.ClientConnect(Sender: TObject);
var
  S: String;
begin
  Client.Sendln('GET / HTTP/1.0');
  Client.SendLn('');
end;

OnConnect 事件处理程序 (RTSP)

procedure TForm1.ClientConnect(Sender: TObject);
var
  S: String;
begin
  Client.SendLn('OPTIONS * RTSP/1.0');
  Client.SendLn('CSeq:0');
  Client.SendLn('');
end;

OnReceive 事件处理程序

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 事件处理程序

procedure TForm1.ClientError(Sender: TObject; SocketError: Integer);
begin
  Log.Lines.Append('> ERROR '+IntToStr(SocketError));
end;

OnReceive 事件从未被调用,我连接的任何服务器都没有返回任何内容。

我在这里做错了什么?

参考文献

这些是我引用的一些链接:

我正在使用的相机是Grandstream GXV3601LL

更新

我断定问题出在 RTSP 服务器上,并已在 Grandstream 网站的论坛上提问。该代码确实适用于其他服务器连接。

【问题讨论】:

  • 实际上,它适用于 HTTP,但还不适用于 RTSP...
  • 请问您为什么使用年代久远的TTCPClient? Indy 更容易使用...
  • 我只是将一个示例放在一起,以确保在我在这里开始真正的项目之前了解一般的沟通概念。
  • 所以看来我必须将这个问题转给相机的供应商,因为它确实适用于 Youtube 等 RTSP 源。

标签: delphi sockets delphi-xe2 rtsp tcp-ip


【解决方案1】:

这对我有用,这取决于您是否处于阻塞模式:

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.

编辑

这是一个使用 RTSP 服务器的真实示例(本例中为 youtube) 我使用了 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.

【讨论】:

  • 嗯,使用您的示例对我来说确实有效,但是当我输入 RTSP 摄像机的 IP 时,它失败并出现套接字错误 10053
  • 错误 10053 是 WSAECONNABORTED,因此似乎相机不允许您的连接。我们在这里谈论的是什么品牌的相机?
  • 我还验证了所有相机的设置,包括一项允许匿名未经身份验证的查看
  • 应该是可行的,你只需要包含一个授权元素。看看这个页面的指针:forum.videolan.org/viewtopic.php?f=13&t=44780
  • 我想我必须接受你的回答,因为它确实回答了这个问题,但我仍然有这些特定相机没有响应的问题。我已经在 Grandstream 的论坛上发布了一个关于此的问题。
【解决方案2】:

OnReceive 事件未被调用的原因是因为TTCPClient 不是一个异步组件,就像您正在尝试处理它一样。 OnReceive 事件的工作方式与旧的 TClientSocket.OnRead 事件相同。 OnReceive 事件仅在 ReceiveBuf() 方法内部调用(ReceiveLn() 在内部调用 ReceiveBuf())。传递给OnReceive 事件的数据与ReceiveBuf() 方法在输出中返回的数据相同。您有一个 catch-22 情况 - 您在调用 ReceiveLn() 之前正在等待 OnReceive 事件,但在您先调用 ReceiveLn() 之前不会触发 OnReceive。如果您想异步使用TTCPClient,则必须在计时器或工作线程中定期调用其ReceiveLn() 方法,NOTOnReceive 事件中。

TTCPClient 组件是 Kylix 旧 CLX 框架的一部分。它不是 VCL 的一部分,甚至不是 FireMonkey,不应该再使用。要么使用旧的 TClientSocket 组件(已弃用但仍然可用),要么更改为另一个组件库,例如 Indy。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多