绑定IP地址只是第一次使用

如何解决绑定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
但是该解决方案仅在第一时间有效!     

解决方法

理论: HttpWebRequest依赖于基础ServicePoint。 ServicePoint代表与URL的实际连接。与您的浏览器保持与请求之间打开的URL的连接并重用该连接(以消除打开和关闭每个请求的连接的开销)非常相似,ServicePoint对HttpWebRequest执行相同的功能。 我认为每次使用HttpWebRequest时都不会调用您为ServicePoint设置的BindIPEndPointDelegate,因为ServicePoint正在重新使用连接。如果您可以强制关闭连接,则下一次对该URL的调用将导致ServicePoint需要再次调用BindIPEndPointDelegate。 不幸的是,似乎没有ServicePoint接口使您能够直接强制关闭连接。 两种解决方案(每种解决方案的结果略有不同) 1)对于每个请求,设置HttpWebRequest.KeepAlive = false。在我的测试中,这导致Bind委托在每个请求中被一对一调用。 2)将ServicePoint ConnectionLeaseTimeout属性设置为零或某个较小的值。这将具有定期强制调用Bind委托的效果(不是每个请求都一对一)。 从文档中:   您可以使用此属性来确保ServicePoint对象的   活动连接不会无限期保持打开状态。该属性是   适用于应该断开连接并   定期重新建立,例如负载平衡方案。      默认情况下,当请求的KeepAlive为true时,MaxIdleTime   属性设置由于以下原因而关闭ServicePoint连接的超时   不活动。如果ServicePoint具有活动连接,则MaxIdleTime   无效,连接将无限期保持打开状态。      当ConnectionLeaseTimeout属性设置为其他值时   -1,并且在经过指定的时间后,通过将KeepAlive设置为来服务请求后,将关闭活动的ServicePoint连接   在该请求中为假。 设置此值会影响ServicePoint对象管理的所有连接。
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 = (servicePoint,remoteEndPoint,retryCount) =>
        {
            IPAddress address = IPAddress.Parse(this.IP);
            return new IPEndPoint(address,0);
        };

        //Will cause bind to be called periodically
        servicePoint.ConnectionLeaseTimeout = 0;

        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
        //will cause bind to be called for each request (as long as the consumer of the request doesn\'t set it back to true!
        req.KeepAlive = false;

        return req;
    }
}
以下(基本)测试结果将为每个请求调用Bind委托:
static void Main(string[] args)
    {
        //Note,I don\'t have a multihomed machine,so I\'m not using the IP in my test implementation.  The bind delegate increments a counter and returns IPAddress.Any.
        UseIP ip = new UseIP(\"111.111.111.111\");

        for (int i = 0; i < 100; ++i)
        {
            HttpWebRequest req = ip.CreateWebRequest(new Uri(\"http://www.yahoo.com\"));
            using (WebResponse response = req.GetResponse())
            {
            }
        }

        Console.WriteLine(string.Format(\"Req: {0}\",UseIP.RequestCount));
        Console.WriteLine(string.Format(\"Bind: {0}\",UseIP.BindCount));
    }
    ,问题可能是代表在每个新请求上都重置了代表。请尝试以下方法:
//servicePoint.BindIPEndPointDelegate = null; // Clears all delegates first,for testing
servicePoint.BindIPEndPointDelegate += delegate
    {
        var address = IPAddress.Parse(this.IP);
        return new IPEndPoint(address,0);
    };
而且据我所知,端点是缓存的,因此即使清除委托在某些情况下也可能不起作用,并且无论如何它们都可能会被重置。在最坏的情况下,您可能会卸载/重新加载应用程序域。     ,我对您的示例进行了一些更改,使其可以在我的计算机上运行:
public HttpWebRequest CreateWebRequest(Uri uri)
{
    HttpWebRequest wr = WebRequest.Create(uri) as HttpWebRequest;
    wr.ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint(Bind);
    return wr;
}
我这样做是因为: 我认为对
FindServicePoint
的调用实际上使用\“ default \” ip来执行请求,甚至没有调用绑定委托到您指定的URI。至少在我的机器上,没有以您提出的方式调用ѭ7(我知道请求是因为我没有设置Proxy并收到代理身份验证错误); 在ServicePointManager的文档中,它声明\“如果该主机和方案存在现有的ServicePoint对象,则ServicePointManager对象将返回现有的ServicePoint对象;否则,该ServicePointManager对象将创建一个新的ServicePoint对象\”可能会始终返回如果URI相同,则返回相同的ServicePoint(也许可以解释为什么随后的调用在同一EndPoint中进行)。 这样,我们可以确保,即使已经请求URI,它也将使用所需的IP,而不是使用
ServicePointManager
的某些先前的“缓存”。     ,我喜欢这个新的类UseIP。 在“指定要与WCF客户端一起使用的传出IP地址”中,有一点关于保护自己免受IPv4 / IPv6差异的影响。 唯一需要更改的是Bind方法,如下所示:
private IPEndPoint Bind(ServicePoint servicePoint,IPEndPoint remoteEndPoint,int retryCount)
{
    if ((null != IP) && (IP.AddressFamily == remoteEndPoint.AddressFamily))
        return new IPEndPoint(this.IP,0);
    if (AddressFamily.InterNetworkV6 == remoteEndPoint.AddressFamily)
        return new IPEndPoint(IPAddress.IPv6Any,0);
    return new IPEndPoint(IPAddress.Any,0);
}
re:Bind方法被多次调用。 对我有用的是在添加任何委托链接之前将其删除。
ServicePoint servicePoint = ServicePointManager.FindServicePoint(uri);
servicePoint.BindIPEndPointDelegate -= this.Bind;   // avoid duplicate calls to Bind
servicePoint.BindIPEndPointDelegate += this.Bind;
我也喜欢缓存UseIP对象的想法。因此,我将此静态方法添加到UseIP类。
private static Dictionary<IPAddress,UseIP> _eachNIC = new Dictionary<IPAddress,UseIP>();
public static UseIP ForNIC(IPAddress nic)
{
    lock (_eachNIC)
    {
        UseIP useIP = null;
        if (!_eachNIC.TryGetValue(nic,out useIP))
        {
            useIP = new UseIP(nic);
            _eachNIC.Add(nic,useIP);
        }
        return useIP;
    }
}
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-