前言:稍微介绍下这个代码的用途,在做某些功能的时候,我们可能会用到IP代理,购买IP的时候也是可以选择长期高质量IP或者短失效但量大的IP,这个主要根据用途来购买;这里就是基于大量短失效IP做的一个IP调度,尽可能保证IP能够物尽其用。.
-
首先定义一个
IPPool
类,然后在构造函数中传入以下参数public class IPPool
{
readonly string _ipUrl, _checkUrl;
readonly int _saveCount;
readonly bool _loopUse;
public ConcurrentQueue<string> IPQueue = new ConcurrentQueue<string>();
/// <summary>
/// 代理IP池
/// </summary>
/// <param name="ipUrl">代理IP的获取网址</param>
/// <param name="checkUrl">检查IP可用性的网址</param>
/// <param name="saveCount">IP池的存储量</param>
/// <param name="loopUse">是否循环使用</param>
public IPPool(string ipUrl, string checkUrl, int saveCount, bool loopUse=true)
{
_ipUrl = ipUrl;
_checkUrl = checkUrl;
_saveCount = saveCount;
_loopUse = loopUse;
}
-
解析网页上的IP地址,这里使用虚方法,以方便可以重写解析方法,应对不同的数据类型
/// <summary>
/// 解析网址IP
/// </summary>
/// <returns></returns>
protected virtual List<string> Parse()
{
List<string> list = new List<string>();
try
{
HttpClient httpClient = new HttpClient();
httpClient.Timeout = new TimeSpan(0, 0, 10);
var result = httpClient.GetStringAsync(_ipUrl).Result;
JObject jobj = JObject.Parse(result);
if (jobj["code"].ToString() == "1")
{
JArray jarr = (JArray)jobj["data"];
foreach (var item in jarr)
{
string ip = item["ip"].ToString() + ":" + item["port"].ToString();
list.Add(ip);
}
}
}
catch { }
return list;
}
-
检查IP可用性,这里可以使用你需要访问的网址或者百度进行Get,保证可以访问到即可,同样使用虚方法定义
/// <summary>
/// 检查IP可用性
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
protected virtual bool Check(string ip)
{
HttpClient httpClient = new HttpClient();
httpClient.Timeout = new TimeSpan(0, 0, 10);
bool result = httpClient.GetAsync(_checkUrl).Result.StatusCode == HttpStatusCode.OK;
return result;
}
-
开始获取,使用定时器获取,同样因为有设置队列的最大值,所以只有当低于这个阈值时才会进行补充,防止IP浪费的同时保证IP充足够用
/// <summary>
/// 开始获取
/// </summary>
/// <param name="interval">获取间隔</param>
public virtual void Start(double interval)
{
System.Timers.Timer timer = new System.Timers.Timer(interval);
timer.Elapsed += (s, e) =>
{
if (IPQueue.Count < _saveCount)
{
List<string> list = Parse();
foreach (var ip in list)
{
IPQueue.Enqueue(ip);
}
}
};
timer.Start();
}
-
获取IP,从队列中获取,如果设置了循环使用的话,不失效可以一直使用,进一步保证IP资源
/// <summary>
/// 获取IP
/// </summary>
/// <returns></returns>
public virtual string Get()
{
string ip = null;
while (IPQueue.Count > 0)
{
IPQueue.TryPeek(out ip);
if (!string.IsNullOrEmpty(ip)&&Check(ip))
{
if (!_loopUse)
{
IPQueue.TryDequeue(out ip);
}
break;
}
else
{
IPQueue.TryDequeue(out string result);
}
}
return ip;
}
}
-
为方便测试,我们自定义一个类继承
IPPool
,然后重写Parse
以及Check
方法public IPHelper(string ipUrl, string checkUrl, int saveCount, bool loopUse = true) : base(ipUrl, checkUrl, saveCount,loopUse)
{
}
protected override List<string> Parse()
{
List<string> list = new List<string>();
list.Add(DateTime.Now.Ticks.ToString());
return list;
}
protected override bool Check(string ip)
{
return true;
}
-
最后调用下看看效果
private async void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
IPHelper iPHelper = new IPHelper("", "", 10,false);
iPHelper.Start(200);
for (int i = 0; i < 5; i++)
{
string ip = iPHelper.Get();
if (ip != null)
{
listBox1.Items.Add(ip);
}
await Task.Delay(500);
}
}
private async void button2_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
IPHelper iPHelper = new IPHelper("", "", 10);
iPHelper.Start(200);
for (int i = 0; i < 5; i++)
{
string ip = iPHelper.Get();
if (ip != null)
{
listBox1.Items.Add(ip);
}
await Task.Delay(500);
}
}
实现效果: