爬虫学习笔记,Net的DNS解析模块

     
目前在做爬虫的功课,今日求学的内容是有关DNS解析模块的构建的。使用的库为ACRUISERSoft.Tools.Net,它是二个格外强劲的开源DNS控件库,包蕴.Net
SPF validation, SenderID validation以及DNS Client、DNS
Server接口。使用该接口可轻易达成DNS客户请求端及服务器解析端。

项目地址:,

Nuget包地址:。

先是引进Nuget包:

 

Install-Package ARSoft.Tools.Net

 

 

下边开始具体落实:

/// <summary>
/// DNS解析
/// </summary>
/// <param name="dnsServer">DNS服务器IP</param>
/// <param name="timeOut">解析超时时间</param>
/// <param name="url">解析网址</param>
/// <param name="isSuccess">是否解析成功</param>
/// <returns>解析到的IP信息</returns>
public static IPAddress DnsResolver(string dnsServer, int timeOut, string url, out bool isSuccess)
{
    //初始化DnsClient,第一个参数为DNS服务器的IP,第二个参数为超时时间
    var dnsClient = new DnsClient(IPAddress.Parse(dnsServer), timeOut);
    //解析域名。将域名请求发送至DNS服务器解析,第一个参数为需要解析的域名,第二个参数为
    //解析类型, RecordType.A为IPV4类型
    //DnsMessage dnsMessage = dnsClient.Resolve("www.sina.com", RecordType.A);
    var s = new Stopwatch();
    s.Start();
    var dnsMessage = dnsClient.Resolve(DomainName.Parse(url));
    s.Stop();
    Console.WriteLine(s.Elapsed.Milliseconds);
    //若返回结果为空,或者存在错误,则该请求失败。
    if (dnsMessage == null || (dnsMessage.ReturnCode != ReturnCode.NoError && dnsMessage.ReturnCode != ReturnCode.NxDomain))
    {
        isSuccess= false;
    }
    //循环遍历返回结果,将返回的IPV4记录添加到结果集List中。
    if (dnsMessage != null)
        foreach (var dnsRecord in dnsMessage.AnswerRecords)
        {
            var aRecord = dnsRecord as ARecord;
            if (aRecord == null) continue;
            isSuccess = true;
            return aRecord.Address;
        }
    isSuccess= false;
    return null;
}

调用方法:

bool isSuccess;
IPAddress ip = DnsResolver("223.5.5.5", 200, "shaoweicloud.cn", out isSuccess);
if (isSuccess)
    Console.WriteLine(ip);

 

爬虫学习笔记,Net的DNS解析模块。     
近年来在做爬虫的作业,前几日学习的始末是关于DNS解析模块的制作的。使用的库为A奇骏Soft.Tools.Net,它是一个相当强劲的开源DNS控件库,蕴含.Net
SPF validation, SenderID validation以及DNS Client、DNS
Server接口。使用该接口可轻便实现DNS客户请求端及服务器解析端。

类型地址:,

Nuget包地址:。

首先引入Nuget包:

 

Install-Package ARSoft.Tools.Net

 

 

上面发轫实际完结:

/// <summary>
/// DNS解析
/// </summary>
/// <param name="dnsServer">DNS服务器IP</param>
/// <param name="timeOut">解析超时时间</param>
/// <param name="url">解析网址</param>
/// <param name="isSuccess">是否解析成功</param>
/// <returns>解析到的IP信息</returns>
public static IPAddress DnsResolver(string dnsServer, int timeOut, string url, out bool isSuccess)
{
    //初始化DnsClient,第一个参数为DNS服务器的IP,第二个参数为超时时间
    var dnsClient = new DnsClient(IPAddress.Parse(dnsServer), timeOut);
    //解析域名。将域名请求发送至DNS服务器解析,第一个参数为需要解析的域名,第二个参数为
    //解析类型, RecordType.A为IPV4类型
    //DnsMessage dnsMessage = dnsClient.Resolve("www.sina.com", RecordType.A);
    var s = new Stopwatch();
    s.Start();
    var dnsMessage = dnsClient.Resolve(DomainName.Parse(url));
    s.Stop();
    Console.WriteLine(s.Elapsed.Milliseconds);
    //若返回结果为空,或者存在错误,则该请求失败。
    if (dnsMessage == null || (dnsMessage.ReturnCode != ReturnCode.NoError && dnsMessage.ReturnCode != ReturnCode.NxDomain))
    {
        isSuccess= false;
    }
    //循环遍历返回结果,将返回的IPV4记录添加到结果集List中。
    if (dnsMessage != null)
        foreach (var dnsRecord in dnsMessage.AnswerRecords)
        {
            var aRecord = dnsRecord as ARecord;
            if (aRecord == null) continue;
            isSuccess = true;
            return aRecord.Address;
        }
    isSuccess= false;
    return null;
}

调用方法:

bool isSuccess;
IPAddress ip = DnsResolver("223.5.5.5", 200, "shaoweicloud.cn", out isSuccess);
if (isSuccess)
    Console.WriteLine(ip);

 

     
在此之前大家曾经根据ARSoft.Tools.Net简单的讲完毕了DNS解析模块的成效,不过当品质要求提高时,每二次爬取都要开始展览DNS请求,甚至很有望1段时间内每一回请求的都以1致的地点,频仍的DNS请求就会成为性能瓶颈,所以大家要因此缓存机制将DNS解析结果缓存下来,下降DNS解析操作,进步系统天性。

那般,大家依据以前封装的MemoryCacheHelper类对DnsResolver类举行更动:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using ARSoft.Tools.Net;
using ARSoft.Tools.Net.Dns;
using Mem = Crawler.Common.MemoryCacheHelper;

namespace Crawler.Protocol
{
public class DnsResolver
{
public TimeSpan TimeSpan { get; set; }
public string Url { get; set; }
public ARecord Record { get; set; }
public string DnsServer { get; set; }
public int TimeOut { get; set; }
public ReturnCode ReturnCode { get; set; }
public bool IsSuccess { get; private set; }
public TimeSpan TimeToLive { get; set; }
public DnsResolver(string url, string dnsServer = “223.5.5.5”, int timeOut = 10000)
{
Url = url;
DnsServer = dnsServer;
TimeOut = timeOut;
IsSuccess = false;
if (Mem.Contains(url))
Fill(Mem.Get(url));
else
Dig();
}

private void Fill(DnsResolver resolver)
{
TimeSpan = resolver.TimeSpan;
Url = resolver.Url;
Record = resolver.Record;
DnsServer = resolver.DnsServer;
TimeOut = resolver.TimeOut;
ReturnCode = resolver.ReturnCode;
IsSuccess = resolver.IsSuccess;
}

public void Dig()
{
//开始化DnsClient,第2个参数为DNS服务器的IP,第一个参数为超时时间
var dnsClient = new DnsClient(IPAddress.Parse(DnsServer), 提姆eOut);
var s = new Stopwatch();
s.Start();
//解析域名。将域名请求发送至DNS服务器解析,参数为索要分析的域名
var dnsMessage = dnsClient.Resolve(DomainName.Parse(Url));
s.Stop();
TimeSpan = s.Elapsed;
//若重临结果为空,也许存在指鹿为马,则该请求退步。
if (dnsMessage == null || (dnsMessage.ReturnCode != ReturnCode.NoError && dnsMessage.ReturnCode != ReturnCode.NxDomain))
IsSuccess = false;
//循环遍历再次回到结果,将重临的IPV4笔录增多到结果集List中。
if (dnsMessage != null)
{
if (dnsMessage.AnswerRecords.Count > 0)
{
Record = dnsMessage.AnswerRecords[0] as ARecord;
if (Record != null)
{
IsSuccess = true;
TimeToLive=new TimeSpan(0,0,Record.TimeToLive);
Mem.Add(Url, this, TimeToLive);
}
}
}
if (dnsMessage != null) ReturnCode = dnsMessage.ReturnCode;
}
}
}

如此那般,每一次做完DNS解析后,会依照域名的TTL将分析结果缓存下来,下次询问时方可平昔调用缓存,升高系统脾性。

0.什么是Redis

Redis是1个开源的行使ANSI
C语言编写、帮衬网络、可依照内存亦可持久化的日志型、Key-Value数据库,并提供两种语言的API

—维基百科

一.与其余用户状态保存方案相比较

style=”color: #000000;”>1般开荒中用户境况使用session或然cookie,两种艺术种种利弊。

style=”color: #000000;”>Session:在InProc情势下轻易丢失,并且引起并发难题。假使利用SQLServer或然SQLServer方式又费用了品质

style=”color: #000000;”>Cookie则轻易将部分用户消息暴光,加解密同样也消耗了质量。

Redis选拔那样的方案化解了多少个问题,

一.Redis存取进度快。

二.用户数据不便于遗失。

3.用户多的情状下轻易帮忙集群。

4.能够查阅在线用户。

5.能够落到实处用户1处登六。(通过代码完结,后续介绍)

陆.协理持久化。(当然大概没什么用)

2.达成思路

style=”color: #000000;”>一.大家了然session其实是在cookie中保留了三个sessionid,用户每趟访问都将sessionid发给服务器,服务器通过ID查找用户对应的情事数据。

style=”color: #000000;”>在此间自个儿的处理方式也是在cookie中定义三个sessionid,先后须求获取用户景况时将sessionid做为key在Redis中索求。

style=”color: #000000;”>二.而且session协助用户在一按期期不访问将session回收。

style=”color: #000000;”>借用Redis中Keys援助过期时刻的表征扶助那么些意义,不过在续期方面须要程序活动拦截请求调用这几个点子(demo有例子)

上面伊始代码表达

叁.Redis调用接口

首先引述ServiceStack相关DLL。

style=”color: #000000;”>在web.config增多布署,这么些布局用来安装Redis调用地址每台服务用【,】隔离。主机写在首先位

 

    1 <appSettings>
    2 
    3     <!--每台Redis之间用,分割.第一个必须为主机-->
    4     <add key="SessionRedis" value="127.0.0.1:6384,127.0.0.1:6384"/>
    5 
    6 </appSettings>

初步化配置

static Managers()
{
string sessionRedis= ConfigurationManager.AppSettings[“SessionRedis”];
string timeOut = ConfigurationManager.AppSettings[“SessionRedisTimeOut”];

if (string.IsNullOrEmpty(sessionRedis))
{
throw new Exception(“web.config 贫乏配置SessionRedis,每台Redis之间用,分割.第三个必须为主机”);
}

if (string.IsNullOrEmpty(timeOut)==false)
{
TimeOut = Convert.ToInt32(timeOut);
}

var host = sessionRedis.Split(char.Parse(“,”));
var writeHost = new string[] { host[0] };
var readHosts = host.Skip(1).ToArray();

ClientManagers = new PooledRedisClientManager(writeHost, readHosts, new RedisClientManagerConfig
{
马克斯WritePoolSize = writeReadCount,//“写”链接池链接数
马克斯ReadPoolSize = writeReadCount,//“读”链接池链接数
AutoStart = true
});
}

为了调控有益写了3个委托

///

/// 写入
///

///
/// ///
public F TryRedisWrite(Func doWrite)
{
PooledRedisClientManager prcm = new Managers().GetClientManagers();
IRedisClient client = null;
try
{
using (client = prcm.GetClient())
{
return doWrite(client);
}
}
catch (RedisException)
{
throw new Exception(“Redis写入至极.Host:” + client.Host + “,Port:” + client.Port);
}
finally
{
if (client != null)
{
client.Dispose();
}
}
}

叁个调用的事例其余的具体看源码

///

/// 以Key/Value的形式存储对象到缓存中
///

/// 对象类别
/// 要写入的集合 public void KSet(Dictionary value)
{
Func fun = (IRedisClient client) =>
{
client.SetAll(value);
return true;
};

TryRedisWrite(fun);
}

4.实现Session

按上边说的给cookie写1个sessionid

///

/// 用户状态管理
///

public class Session
{
///

/// 初始化
///

/// public Session(HttpContextBase 美高梅开户网址 ,_context)
{
var context = _context;
var cookie = context.Request.Cookies.Get(SessionName);
if (cookie == null || string.IsNullOrEmpty(cookie.Value))
{
SessionId = NewGuid();
context.Response.Cookies.Add(new HttpCookie(SessionName, SessionId));
context.Request.Cookies.Add(new HttpCookie(SessionName, SessionId));
}
else
{
SessionId = cookie.Value;
}
}

}

去存取用户的章程

///

/// 获取当前用户信息
///

///
///
public object Get() where T:class,new()
{
return new RedisClient().KGet(SessionId);
}

///

/// 用户是否在线
///

///
public bool IsLogin()
{
return new RedisClient().KIsExist(SessionId);
}

///

/// 登录
///

///
/// public void Login(T obj) where T : class,new()
{
new RedisClient().KSet(SessionId, obj, new TimeSpan(0, Managers.TimeOut, 0));
}

6.续期

暗中认可用户没访问超过三拾秒钟注销用户的记名境况,所以用户每一次访问都要将用户的吊销时间推移28分钟

那要求调用Redis的续期方法

///

/// 延期
///

/// /// public void KSetEntryIn(string key, TimeSpan expiresTime)
{
Func fun = (IRedisClient client) =>
{
client.ExpireEntryIn(key, expiresTime);
return false;
};

TryRedisWrite(fun);
}

封装今后

///

/// 续期
///

public void Postpone()
{
new RedisClient().KSetEntryIn(SessionId, new TimeSpan(0, Managers.TimeOut, 0));
}

那里本身动用了MVC三中的ActionFilter,拦截用户的有着请求

namespace Test
{
public class SessionFilterAttribute : ActionFilterAttribute
{
///

/// 每次请求都续期
///

/// public override void OnActionExecuting(ActionExecutingContext filterContext)
{
new Session(filterContext.HttpContext).Postpone();
}
}
}

在Global.asax中要登记一下

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new SessionFilterAttribute());
}

protected void Application_Start()
{
RegisterGlobalFilters(GlobalFilters.Filters);
}

伍.调用艺术

为了便利调用借用四.0中的新特点,把Controller增多四个扩张属性

public static class ExtSessions
{public static Session SessionExt(this Controller controller)
{
return new Session(controller.HttpContext);
}
}

调用方法

public class HomeController : Controller
{
public ActionResult Index()
{
this.SessionExt().IsLogin();
return View();
}
}

陆.代码下载

点击下载

7.后续

SessionManager包罗 获取用户列表数量,注销有个别用户,依据用户ID获取用户消息,在线用户对象列表,在线用户SessionId列表等办法

 

 

 

 

 

懂的接纳办法后大家得以对它做进一步封装,获得DnsResolver类:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using ARSoft.Tools.Net;
using ARSoft.Tools.Net.Dns;

namespace Crawler.Protocol
{
public class DnsResolver
{
public TimeSpan TimeSpan { get; set; }
public string Url { get; set; }
public List Record { get; set; }
public string DnsServer { get; set; }
public int TimeOut { get; set; }
public ReturnCode ReturnCode { get; set; }
public bool IsSuccess { get; private set; }
public DnsResolver(string url, string dnsServer = “223.5.5.5”, int timeOut = 200)
{
Url = url;
DnsServer = dnsServer;
TimeOut = timeOut;
Record=new List();
Dig();
}

public void Dig()
{
//初阶化DnsClient,第四个参数为DNS服务器的IP,第一个参数为超时时间
var dnsClient = new DnsClient(IPAddress.Parse(DnsServer), TimeOut);
var s = new Stopwatch();
s.Start();
//解析域名。将域名请求发送至DNS服务器解析,参数为急需分析的域名
var dnsMessage = dnsClient.Resolve(DomainName.Parse(Url));
s.Stop();
提姆eSpan = s.Elapsed;
//若重临结果为空,大概存在错误,则该请求战败。
if (dnsMessage == null || (dnsMessage.ReturnCode != ReturnCode.NoError && dnsMessage.ReturnCode != ReturnCode.NxDomain))
IsSuccess = false;
//循环遍历再次来到结果,将回到的IPV4记下增加到结果集List中。
if (dnsMessage != null)
foreach (var dnsRecord in dnsMessage.AnswerRecords)
{
var aRecord = dnsRecord as ARecord;
if (aRecord == null) continue;
IsSuccess = true;
Record.Add(aRecord);
}
if (dnsMessage != null) ReturnCode = dnsMessage.ReturnCode;
}
}
}

调用方法:

DnsResolver dns = new DnsResolver("shaoweicloud.cn");
if (dns.IsSuccess)
    Console.WriteLine(dns.Record[0]);

 

        
至此,DNS解析模块就基本告竣了,至于为什么标题中标注了半成品,是因为自个儿想在大旨的DNS解析功用的底子上依照分析到DNS音信中的TTL做一套消息缓存机制,减弱不要求的双重查询,近来还在设想使用何种方法,后续落成会更新。

懂的使用办法后大家得以对它做进一步封装,获得DnsResolver类:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using ARSoft.Tools.Net;
using ARSoft.Tools.Net.Dns;

namespace Crawler.Protocol
{
public class DnsResolver
{
public TimeSpan TimeSpan { get; set; }
public string Url { get; set; }
public List Record { get; set; }
public string DnsServer { get; set; }
public int TimeOut { get; set; }
public ReturnCode ReturnCode { get; set; }
public bool IsSuccess { get; private set; }
public DnsResolver(string url, string dnsServer = “223.5.5.5”, int timeOut = 200)
{
Url = url;
DnsServer = dnsServer;
TimeOut = timeOut;
Record=new List();
Dig();
}

public void Dig()
{
//初叶化DnsClient,首个参数为DNS服务器的IP,第二个参数为超时时间
var dnsClient = new DnsClient(IPAddress.Parse(DnsServer), TimeOut);
var s = new Stopwatch();
s.Start();
//解析域名。将域名请求发送至DNS服务器解析,参数为急需分析的域名
var dnsMessage = dnsClient.Resolve(DomainName.Parse(Url));
s.Stop();
TimeSpan = s.Elapsed;
//若重返结果为空,恐怕存在不当,则该请求失利。
if (dnsMessage == null || (dnsMessage.ReturnCode != ReturnCode.NoError && dnsMessage.ReturnCode != ReturnCode.NxDomain))
IsSuccess = false;
//循环遍历重临结果,将回来的IPV四记录增多到结果集List中。
if (dnsMessage != null)
foreach (var dnsRecord in dnsMessage.AnswerRecords)
{
var aRecord = dnsRecord as ARecord;
if (aRecord == null) continue;
IsSuccess = true;
Record.Add(aRecord);
}
if (dnsMessage != null) ReturnCode = dnsMessage.ReturnCode;
}
}
}

调用方法:

DnsResolver dns = new DnsResolver("shaoweicloud.cn");
if (dns.IsSuccess)
    Console.WriteLine(dns.Record[0]);

 

        
至此,DNS解析模块就着力告竣了,至于何以标题中标注了半成品,是因为本人想在基本的DNS解析成效的根基上依照分析到DNS新闻中的TTL做壹套音信缓存机制,裁减不必要的再一次查询,近期还在思量动用何种措施,后续达成会更新。

发表评论

电子邮件地址不会被公开。 必填项已用*标注