C#根据IP查询省份、城市,纯真IP库实现方式+无IP库实现方式

首先,要获取到一个IP地址,可参照上文:http://blog.csdn.net/konw_nothing/article/details/8888526


第一种方式:

读取纯真IP库的封装类:

要下载数据文件的话,直接百度搜“纯真ip数据库”,一般就能找到了。文件名通常是 qqwry.dat

using System;
using System.IO;
using System.Text;

/// 
/// IP对象类,该对象包含所属国家和地区
/// 
public class IPLocation
{
    public string ISP { get; set; }
    public string Area { get; set; }
}

/// 
/// 读取QQ纯真IP数据库 
///     
public class QQWry
{
    //第一种模式 
    private const byte REDIRECT_MODE_1 = 0x01;

    //第二种模式 
    private const byte REDIRECT_MODE_2 = 0x02;

    //每条记录长度 
    private const int IP_RECORD_LENGTH = 7;

    //数据库文件 
    private FileStream ipFile = null;

    private const string unISP = "未知ISP";
    private const string unArea = "未知地区";

    //索引开始位置 
    private long ipBegin;

    //索引结束位置 
    private long ipEnd;

    //IP地址对象 
    private IPLocation loc;

    //存储文本内容 
    private byte[] buf;

    //存储3字节 
    private byte[] b3;

    //存储4字节 
    private byte[] b4;

    ///  
    /// 构造函数 
    ///  
    /// IP数据库文件绝对路径 
    ///  
    public QQWry(string ipfile)
    {
        buf = new byte[100];
        b3 = new byte[3];
        b4 = new byte[4];
        lock (this)
        {
            ipFile = new FileStream(ipfile, FileMode.Open);
            ipBegin = ReadLong4(0);
            ipEnd = ReadLong4(4);
            loc = new IPLocation();
        }
    }

    ///  
    /// 搜索IP地址搜索 
    ///  
    ///  
    ///  
    public IPLocation SearchIPLocation(string ip)
    {
        //将字符IP转换为字节 
        string[] ipSp = ip.Split('.');
        if (ipSp.Length != 4)
        {
            ip = "127.0.0.1";
            ipSp = ip.Split('.');           
        }
        byte[] IP = new byte[4];
        for (int i = 0; i < IP.Length; i++)
        {
            IP[i] = (byte)(Int32.Parse(ipSp[i]) & 0xFF);
        }

        IPLocation local = null;
        long offset = LocateIP(IP);

        if (offset != -1)
        {
            local = getIPLocation(offset);
        }

        if (local == null)
        {
            local = new IPLocation();
            local.Area = unArea;
            local.ISP = unISP;
        }
        return local;
    }

    ///  
    /// 取得具体信息 
    ///  
    ///  
    ///  
    private IPLocation getIPLocation(long offset)
    {
        ipFile.Position = offset + 4;
        //读取第一个字节判断是否是标志字节 
        byte one = (byte)ipFile.ReadByte();
        if (one == REDIRECT_MODE_1)
        {
            //第一种模式 
            //读取国家偏移 
            long countryOffset = ReadLong3();
            //转至偏移处 
            ipFile.Position = countryOffset;
            //再次检查标志字节 
            byte b = (byte)ipFile.ReadByte();
            if (b == REDIRECT_MODE_2)
            {
                loc.Area = ReadString(ReadLong3());
                ipFile.Position = countryOffset + 4;
            }
            else
                loc.Area = ReadString(countryOffset);

            //读取运营商标志
            loc.ISP = ReadArea(ipFile.Position);

        }
        else if (one == REDIRECT_MODE_2)
        {
            //第二种模式 
            loc.Area = ReadString(ReadLong3());
            loc.ISP = ReadArea(offset + 8);
        }
        else
        {
            //普通模式 
            loc.Area = ReadString(--ipFile.Position);
            loc.ISP = ReadString(ipFile.Position);
        }
        ipFile.Close();
        return loc;
    }

    ///  
    /// 读取地区名称 
    ///  
    ///  
    ///  
    private string ReadArea(long offset)
    {
        ipFile.Position = offset;
        byte one = (byte)ipFile.ReadByte();
        if (one == REDIRECT_MODE_1 || one == REDIRECT_MODE_2)
        {
            long areaOffset = ReadLong3(offset + 1);
            return (areaOffset == 0) ? unArea : ReadString(areaOffset);
        }
        else
        {
            return ReadString(offset);
        }
    }

    ///  
    /// 读取字符串 
    ///  
    ///  
    ///  
    private string ReadString(long offset)
    {
        ipFile.Position = offset;
        int i = 0;
        for (i = 0, buf[i] = (byte)ipFile.ReadByte(); buf[i] != (byte)(0); buf[++i] = (byte)ipFile.ReadByte()) ;
        return (i > 0) ? Encoding.Default.GetString(buf, 0, i) : "";
    }

    ///  
    /// 查找IP地址所在的绝对偏移量 
    ///  
    ///  
    ///  
    private long LocateIP(byte[] ip)
    {
        long m = 0;
        int r;

        //比较第一个IP项 
        ReadIP(ipBegin, b4);
        r = CompareIP(ip, b4);
        if (r == 0)
            return ipBegin;
        else if (r < 0)
            return -1;
        //开始二分搜索 
        for (long i = ipBegin, j = ipEnd; i < j; )
        {
            m = this.GetMiddleOffset(i, j);
            ReadIP(m, b4);
            r = CompareIP(ip, b4);
            if (r > 0)
                i = m;
            else if (r < 0)
            {
                if (m == j)
                {
                    m = j -= IP_RECORD_LENGTH;
                }
                else
                {
                    j = m;
                }
            }
            else
                return ReadLong3(m + 4);
        }
        m = ReadLong3(m + 4);
        ReadIP(m, b4);
        return (CompareIP(ip, b4) <= 0) ? m : -1;
    }

    ///  
    /// 从当前位置读取四字节,此四字节是IP地址 
    ///  
    ///  
    ///  
    private void ReadIP(long offset, byte[] ip)
    {
        ipFile.Position = offset;
        ipFile.Read(ip, 0, ip.Length);
        byte tmp = ip[0];
        ip[0] = ip[3];
        ip[3] = tmp;
        tmp = ip[1];
        ip[1] = ip[2];
        ip[2] = tmp;
    }

    ///  
    /// 比较IP地址是否相同 
    ///  
    ///  
    ///  
    /// 0:相等,1:ip大于beginIP,-1:小于 
    private int CompareIP(byte[] ip, byte[] beginIP)
    {
        for (int i = 0; i < 4; i++)
        {
            int r = CompareByte(ip[i], beginIP[i]);
            if (r != 0)
                return r;
        }
        return 0;
    }

    ///  
    /// 比较两个字节是否相等 
    ///  
    ///  
    ///  
    ///  
    private int CompareByte(byte bsrc, byte bdst)
    {
        if ((bsrc & 0xFF) > (bdst & 0xFF))
            return 1;
        else if ((bsrc ^ bdst) == 0)
            return 0;
        else
            return -1;
    }

    ///  
    /// 从当前位置读取4字节,转换为长整型 
    ///  
    ///  
    ///  
    private long ReadLong4(long offset)
    {
        long ret = 0;
        ipFile.Position = offset;
        ret |= (ipFile.ReadByte() & 0xFF);
        ret |= ((ipFile.ReadByte() << 8) & 0xFF00);
        ret |= ((ipFile.ReadByte() << 16) & 0xFF0000);
        ret |= ((ipFile.ReadByte() << 24) & 0xFF000000);

        return ret;
    }

    ///  
    /// 根据当前位置,读取3字节 
    ///  
    ///  
    ///  
    private long ReadLong3(long offset)
    {
        long ret = 0;
        ipFile.Position = offset;
        ret |= (ipFile.ReadByte() & 0xFF);
        ret |= ((ipFile.ReadByte() << 8) & 0xFF00);
        ret |= ((ipFile.ReadByte() << 16) & 0xFF0000);
        return ret;
    }

    ///  
    /// 从当前位置读取3字节 
    ///  
    ///  
    private long ReadLong3()
    {
        long ret = 0;
        ret |= (ipFile.ReadByte() & 0xFF);
        ret |= ((ipFile.ReadByte() << 8) & 0xFF00);
        ret |= ((ipFile.ReadByte() << 16) & 0xFF0000);
        return ret;
    }

    ///  
    /// 取得begin和end中间的偏移 
    ///  
    ///  
    ///  
    ///  
    private long GetMiddleOffset(long begin, long end)
    {
        long records = (end - begin) / IP_RECORD_LENGTH;
        records >>= 1;
        if (records == 0)
            records = 1;
        return begin + records * IP_RECORD_LENGTH;
    }
}

使用方式:

IPLocation ip = new QQWry(Server.MapPath("~/App_Data/QQWry.Dat")).SearchIPLocation("58.83.255.255");
Response.Write("ISP:" + ip.ISP + "
");//铁通 Response.Write("Area:" + ip.Area);//北京市朝阳区

第二种方式:

使用第三方接口

介绍一种新浪的接口:其他接口大同小异

接口地址:http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip={ip}

public class IpDetail
{
    public string Ret { get; set; }
    public string Start { get; set; }
    public string End { get; set; }
    public string Country { get; set; }
    public string Province { get; set; }
    public string City { get; set; }
    public string District { get; set; }
    public string Isp { get; set; }
    public string Type { get; set; }
    public string Desc { get; set; }
    public static IpDetail Get(string ipAddress, Encoding sourceEncoding)
    {
        string ip = string.Empty;
        if (sourceEncoding == null)
            sourceEncoding = Encoding.UTF8;
        using (var receiveStream = System.Net.WebRequest.Create(string.Format("http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip={0}", ipAddress)).GetResponse().GetResponseStream())
        {
            using (var sr = new StreamReader(receiveStream, sourceEncoding))
            {
                ip = sr.ReadToEnd();
            }
        }
        return !string.IsNullOrEmpty(ip) ? new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize(ip) : null;
    }
}

使用方式:

IpDetail d = IpDetail.Get("58.83.255.255", null);
Response.Write(d.Country + "
"); Response.Write(d.Province + "
"); Response.Write(d.City + "
"); Response.Write(d.Isp);


另外,可以结合两种方式,当纯真库查不出数据时,有可能是纯真库没有及时更新,那么就能用接口方式来获取,一般第三方的IP库还是有保证的。


你可能感兴趣的:(.Net开发)