【问题标题】:TidUDPClient thru proxy serverTidUDPClient 通过代理服务器
【发布时间】:2017-07-11 00:45:11
【问题描述】:

在下面的代码中我有一些相关的问题

var
  UseProxy : Boolean = True;
....
var
  IdUDPClient : TIdUDPClient;
  sText       : string;
begin
  IdUDPClient := TIdUDPClient.Create(nil);
  try
    IdUDPClient.Host := '10.10.10.10';
    IdUDPClient.Port := 5555;
    if UseProxy then begin
      IdUDPClient.TransparentProxy.Enabled := True;
      IdUDPClient.TransparentProxy.Host    := '20.20.20.20';
      IdUDPClient.TransparentProxy.Port    := 8080;
      IdUDPClient.OpenProxy;
    end;
    try
      IdUDPClient.Connect;
    except
      Writeln('Connect Error.');
    end;
    if IdUDPClient.Connected then
      Writeln('Connected')
    else begin
      Writeln('Not Connected');
      Exit;
    end;
    try
      IdUDPClient.Send('Foo');
      try
        sText := IdUDPClient.ReceiveString(1000);
        Writeln('Received: ', sText);
      except
        Writeln('Receive Error.');
      end;
    except
      Writeln('Send Error.');
    end;
    if UseProxy then
      IdUDPClient.CloseProxy;
  finally
    IdUDPClient.Free;
  end;
  Readln;
end.
  1. 为什么try...except 块没有捕获UDP 上的错误 客户端即使主机不可访问或端口已关闭,例如IdUDPClient.Connected 总是True?
  2. 使用代理时,我不确定我的实现是否正确 因为如果 UseProxy 是 True IdUDPClient 尝试直接发送 对10.10.10.10的请求不通过代理服务器。我该如何解决这个问题?我做错了什么?

我的代理测试场景如下:

  • 我的电脑IP30.30.30.30
  • UDP 服务器10.10.10.10
  • 代理服务器(Socks 5)20.20.20.20

30.30.30.0/24 无法到达 10.10.10.1020.20.20.20 可以。

  1. 如果我的 PC 可以直接访问 UDP 服务器并且我将假代理服务器(未使用的 IP 和随机端口)放到客户端。客户端可以访问由于代理已关闭而不应访问的 UDP 服务器。我怎么不能防止这种情况发生?

【问题讨论】:

    标签: delphi proxy udp indy


    【解决方案1】:
    1. UDP 是无连接的,因此Connected 无法告诉您远程对等方是否可达。

      “连接”UDP 套接字只是分配与对等 IP/端口的本地关联。这样,出站数据包仅发送到该对等方,并且仅接受从该对等方接收的数据包。而已。没有实际的连接,就像在 TCP 中一样。

      与 TCP 不同,发送 UDP 数据包只是将数据包转储到网络上,没有确认数据包曾经到达对等方。 Acks 必须在应用层实现。

      至于异常,它们仅在发生实际错误时引发。在 UDP 中,无法访问的主机会导致套接字错误的唯一方法是,如果网络发回一个 ICMP 数据包以指示主机不可访问。 “已连接”的 UDP 套接字将在内部接收此类数据包,并在 后续 与同一对等方读取/发送时开始报告失败。因此,在您的示例中,对 Send() 的调用将永远不会引发有关未到达主机的错误,因为它根本不知道。 ReceiveString() 有更好的机会报告此类错误,但是按照当前的实现方式,它可能会忽略它们,因为它会在实际读取套接字之前检查套接字是否可读(有待处理的 UDP 数据包)。 ICMP 数据包可能无法使套接字进入可读状态。

      由于您在 ReceiveString() 上指定了超时,因此您只需假设在超时时间过后而没有收到实际字符串的情况下对等方已消失。

    2. 您的代码正在绕过代理,因为您没有正确设置 TransparentProxy

      当您访问TransparentProxy 属性时,如果当前没有分配代理组件,则属性getter 会创建一个内部TIdSocksInfo 对象。 TIdSocksInfo 有一个 Version 属性,默认为 svNoSocks。由于您尝试通过 SOCKS v5 代理进行连接,因此您需要将 Version 设置为 svSocks5

      if UseProxy then begin
        (IdUDPClient.TransparentProxy as TIdSocksInfo).Version := svSocks5; // <--
        IdUDPClient.TransparentProxy.Host    := '20.20.20.20';
        IdUDPClient.TransparentProxy.Port    := 8080;
      end;
      

      TransparentProxy.Enabled 属性设置器根本不与TIdSocksInfo 一起使用,它是无操作的。但是,Enabled 属性 getter 根据 TIdSocksInfo.Version 属性的值返回 True/False。

      您无需手动调用OpenProxy()CloseProxy()TIdUDPClient.Connect()TIdUDPClient.Disconnect() 将在启用TransparentProxy 时为您处理。

    现在,说了这么多,试试这个:

    var
      UseProxy : Boolean = True;
      ...
    
    var
      IdUDPClient : TIdUDPClient;
      IdSocksInfo : TIdSocksInfo;
      sText       : string;
    begin
      IdUDPClient := TIdUDPClient.Create(nil);
      try
        IdUDPClient.Host := '10.10.10.10';
        IdUDPClient.Port := 5555;
    
        if UseProxy then begin
          IdSocksInfo := TIdSocksInfo.Create(IdUDPClient);
          IdSocksInfo.Version := svSocks5;
          IdSocksInfo.Host    := '20.20.20.20';
          IdSocksInfo.Port    := 8080;
          IdUDPClient.TransparentProxy := IdSocksInfo;
        end;
    
        try
          IdUDPClient.Connect;
        except
          on E: Exception do begin
            Writeln('Connect Error: ', E.Message);
            Exit;
          end;
        end;
    
        try
          Writeln('Connected.');
    
          try
            IdUDPClient.Send('Foo');
          except
            on E: Exception do begin
              Writeln('Send Error: ', E.Message);
              Exit;
            end;
          end;
    
          try
            sText := IdUDPClient.ReceiveString(1000);
            if sText <> '' then
              Writeln('Received: ', sText)
            else
              Writeln('Nothing Received after 1 second.');
          except
            on E: Exception do begin
              Writeln('Receive Error: ', E.Message);
            end;
          end;
        finally
          IdUDPClient.Disconnect;
        end;
      finally
        IdUDPClient.Free;
      end;
    
    end.
    

    【讨论】:

    • 嗨,雷米,如果 UseProxy = True,我在调用 IdUDPClient.Connect; 时收到 RSSocksServerCommandError
    • RSSocksServerCommandErrorTIdSocksInfo 在收到来自 SOCKS v5 代理的包含错误代码 7(不支持命令)的回复时引发。在这种情况下,TIdUDPClient.Connect() 发送一个 SOCKS5 UDP ASSOCIATE 请求,服务器回复“不支持”。所以这是一个代理方面的问题。
    猜你喜欢
    • 1970-01-01
    • 2016-09-12
    • 1970-01-01
    • 2016-01-06
    • 2019-07-02
    • 1970-01-01
    • 2013-05-09
    • 2016-03-24
    • 1970-01-01
    相关资源
    最近更新 更多