第一次绑定IP地址就可以了
我想从服务器上的一个可用 IP 地址发出 Web 请求,因此我使用此类:
public class UseIP
{
public string IP { get; private set; }
public UseIP(string IP)
{
this.IP = IP;
}
public HttpWebRequest CreateWebRequest(Uri uri)
{
ServicePoint servicePoint = ServicePointManager.FindServicePoint(uri);
servicePoint.BindIPEndPointDelegate = new BindIPEndPoint(Bind);
return WebRequest.Create(uri) as HttpWebRequest;
}
private IPEndPoint Bind(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount)
{
IPAddress address = IPAddress.Parse(this.IP);
return new IPEndPoint(address, 0);
}
}
然后:
UseIP useIP = new UseIP("Valid IP address here...");
Uri uri = new Uri("http://ip.nefsc.noaa.gov");
HttpWebRequest request = useIP.CreateWebRequest(uri);
// Then make the request with the specified IP address
但是该解决方案第一次就有效!
I want to make a web request from one of available IP addresses on server so I use this class:
public class UseIP
{
public string IP { get; private set; }
public UseIP(string IP)
{
this.IP = IP;
}
public HttpWebRequest CreateWebRequest(Uri uri)
{
ServicePoint servicePoint = ServicePointManager.FindServicePoint(uri);
servicePoint.BindIPEndPointDelegate = new BindIPEndPoint(Bind);
return WebRequest.Create(uri) as HttpWebRequest;
}
private IPEndPoint Bind(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount)
{
IPAddress address = IPAddress.Parse(this.IP);
return new IPEndPoint(address, 0);
}
}
Then:
UseIP useIP = new UseIP("Valid IP address here...");
Uri uri = new Uri("http://ip.nefsc.noaa.gov");
HttpWebRequest request = useIP.CreateWebRequest(uri);
// Then make the request with the specified IP address
But the solution just works the first time!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
理论:
HttpWebRequest 依赖于底层 ServicePoint。 ServicePoint 表示与 URL 的实际连接。与浏览器在请求之间保持与 URL 的连接打开并重用该连接(以消除每个请求打开和关闭连接的开销)的方式非常相似,ServicePoint 对 HttpWebRequest 执行相同的功能。
我认为您为 ServicePoint 设置的 BindIPEndPointDelegate 不会在每次使用 HttpWebRequest 时被调用,因为 ServicePoint 正在重用连接。如果您可以强制关闭连接,则下次调用该 URL 应该会导致 ServicePoint 需要再次调用 BindIPEndPointDelegate。
不幸的是,ServicePoint 接口似乎无法让您直接强制关闭连接。
两种解决方案(每种结果略有不同)
1) 对于每个请求,设置 HttpWebRequest.KeepAlive = false。在我的测试中,这导致 Bind 委托在每个请求中都被一对一地调用。
2) 将ServicePoint ConnectionLeaseTimeout 属性设置为零或某个较小的值。这将产生定期强制调用 Bind 委托的效果(而不是针对每个请求一对一)。
来自文档:
设置此值会影响 ServicePoint 对象管理的所有连接。
以下(基本)测试结果是为每个请求调用 Bind 委托:
A theory:
HttpWebRequest relies on an underlying ServicePoint. The ServicePoint represents the actual connection to the URL. Much in the same way your browser keeps a connection to a URL open between requests and reuses that connection (to eliminate the overhead of opening and closing the connection with each request), ServicePoint performs the same function for HttpWebRequest.
I think that the BindIPEndPointDelegate that you are setting for the ServicePoint is not being called on each use of HttpWebRequest because the ServicePoint is reusing the connection. If you could force the connection to close, then the next call to that URL should cause the ServicePoint to need to call BindIPEndPointDelegate again.
Unfortunately, it doesn't appear that the ServicePoint interface gives you the ability to directly force a connection to close.
Two solutions (each with slightly different results)
1) For each request, set HttpWebRequest.KeepAlive = false. In my test, this caused the Bind delegate to get called one-for-one with each request.
2) Set the ServicePoint ConnectionLeaseTimeout property to zero or some small value. This will have the effect of periodically forcing the Bind delegate to be called (not one-for-one with each request).
From the documentation:
Setting this value affects all connections managed by the ServicePoint object.
The following (basic) test results in the Bind delegate getting called for each request:
问题可能是代表在每个新请求时都会重置。请尝试以下操作:
据我所知,端点会被缓存,因此即使清除委托在某些情况下也可能不起作用,并且无论如何它们都可能会被重置。作为最坏的情况,您可以卸载/重新加载应用程序域。
Problem may be with the delegate getting reset on each new request. Try below:
Also as far as I know, the endpoints are cached so even clearing the delegate may not work in some cases and they may get reset regardless. You may unload/reload the app domain as the worst case scenario.
我对您的示例进行了一些更改并使其在我的机器上工作:
我这样做是因为:
BindIPEndPointDelegate
没有按照您提供的方式调用(我知道发出请求是因为我没有设置代理并收到代理身份验证错误);ServicePointManager
的一些先前的“缓存”。I have changed your example a little and make it work on my machine:
I did that because:
FindServicePoint
actually does the request using the "default" ip, without even calling the binding delegate, to the URI you have specified. In my machine, at least, theBindIPEndPointDelegate
was not called in the way you have presented (I know the request was made because I didn't set the Proxy and got a proxy authentication error);ServicePointManager
.我喜欢这个新类UseIP。
指定要使用的传出 IP 地址使用 WCF 客户端了解如何保护自己免受 IPv4/IPv6 差异的影响。
唯一需要更改的是 Bind 方法,如下所示:
re: Bind 方法被多次调用。
对我有用的是在添加任何委托链接之前删除它。
我也喜欢缓存 UseIP 对象的想法。所以我将这个静态方法添加到 UseIP 类中。
I like this new class UseIP.
There is a point at Specify the outgoing IP Address to use with WCF client about protecting yourself from IPv4/IPv6 differences.
The only thing that would need to change is the Bind method to be like this:
re: the Bind method being called multiple times.
What works for me is to remove any delegate link before I add it.
I also like the idea of caching the UseIP objects. So I added this static method to the UseIP class.