TidUDPClient 通过代理服务器
TidUDPClient thru proxy server
关于下面的一段代码,我有一些相关的问题
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.
- 为什么
try...except
块没有捕获 UDP
上的错误
客户端,即使主机不可访问,端口也关闭,例如IdUDPClient.Connected
总是 True
?
- 使用代理时,我不确定上面的实现是否正确
因为如果
UseProxy
是 True IdUDPClient 尝试直接发送
对 10.10.10.10
的请求不是通过代理服务器。我该如何解决这个问题?我做错了什么?
我的代理测试场景如下:
- 我的电脑IP
30.30.30.30
- UDP 服务器
10.10.10.10
- 代理服务器(Socks 5)
20.20.20.20
30.30.30.0/24
无法达到 10.10.10.10
但 20.20.20.20
可以。
- 如果我的 PC 可以直接访问 UDP 服务器,并且我将假代理服务器(未使用的 IP 和随机端口)连接到客户端。客户端可以访问不应该访问的 UDP 服务器,因为代理已关闭。我怎么不能阻止这种情况?
UDP 是无连接的,因此 Connected
无法告诉您远程对等点是否可达。
"Connecting" UDP 套接字简单地分配与对等方的本地关联 IP/Port。这样,出站数据包仅发送到该对等点,并且仅接受从该对等点接收的数据包。而已。没有像 TCP 那样的实际连接。
并且与 TCP 不同,发送 UDP 数据包只是将数据包转储到网络上,不会确认数据包曾经到达对等方。 ack必须在应用层实现。
至于异常,只有在实际发生错误时才会引发异常。在 UDP 中,无法访问的主机导致套接字错误的唯一方法是网络发回 ICMP 数据包以指示无法访问主机。 "connected" UDP 套接字将在内部接收此类数据包,并在 后续 reads/sends 上与同一对等方开始报告故障。因此,在您的示例中,对 Send()
的调用永远不会引发有关未到达主机的错误,因为它根本不知道。 ReceiveString()
有更好的机会报告此类错误,但是它目前的实现方式可能只是忽略它们,因为它会在实际读取之前检查套接字是否可读(有一个挂起的 UDP 数据包)。 ICMP 数据包可能不会使套接字进入可读状态。
由于您在 ReceiveString()
上指定了超时,如果超时过去但未收到实际字符串,您将不得不假设对等方已经消失。
您的代码绕过了代理,因为您没有正确设置 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
属性 setter 根本不与 TIdSocksInfo
一起使用,它是一个空操作。但是,Enabled
属性getterreturnsTrue/False取决于TIdSocksInfo.Version
属性.
的值
而且您不需要手动调用 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.
关于下面的一段代码,我有一些相关的问题
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.
- 为什么
try...except
块没有捕获UDP
上的错误 客户端,即使主机不可访问,端口也关闭,例如IdUDPClient.Connected
总是True
? - 使用代理时,我不确定上面的实现是否正确
因为如果
UseProxy
是 True IdUDPClient 尝试直接发送 对10.10.10.10
的请求不是通过代理服务器。我该如何解决这个问题?我做错了什么?
我的代理测试场景如下:
- 我的电脑IP
30.30.30.30
- UDP 服务器
10.10.10.10
- 代理服务器(Socks 5)
20.20.20.20
30.30.30.0/24
无法达到 10.10.10.10
但 20.20.20.20
可以。
- 如果我的 PC 可以直接访问 UDP 服务器,并且我将假代理服务器(未使用的 IP 和随机端口)连接到客户端。客户端可以访问不应该访问的 UDP 服务器,因为代理已关闭。我怎么不能阻止这种情况?
UDP 是无连接的,因此
Connected
无法告诉您远程对等点是否可达。"Connecting" UDP 套接字简单地分配与对等方的本地关联 IP/Port。这样,出站数据包仅发送到该对等点,并且仅接受从该对等点接收的数据包。而已。没有像 TCP 那样的实际连接。
并且与 TCP 不同,发送 UDP 数据包只是将数据包转储到网络上,不会确认数据包曾经到达对等方。 ack必须在应用层实现。
至于异常,只有在实际发生错误时才会引发异常。在 UDP 中,无法访问的主机导致套接字错误的唯一方法是网络发回 ICMP 数据包以指示无法访问主机。 "connected" UDP 套接字将在内部接收此类数据包,并在 后续 reads/sends 上与同一对等方开始报告故障。因此,在您的示例中,对
Send()
的调用永远不会引发有关未到达主机的错误,因为它根本不知道。ReceiveString()
有更好的机会报告此类错误,但是它目前的实现方式可能只是忽略它们,因为它会在实际读取之前检查套接字是否可读(有一个挂起的 UDP 数据包)。 ICMP 数据包可能不会使套接字进入可读状态。由于您在
ReceiveString()
上指定了超时,如果超时过去但未收到实际字符串,您将不得不假设对等方已经消失。您的代码绕过了代理,因为您没有正确设置
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
属性 setter 根本不与TIdSocksInfo
一起使用,它是一个空操作。但是,Enabled
属性getterreturnsTrue/False取决于TIdSocksInfo.Version
属性.而且您不需要手动调用
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.