diff --git a/binding/c#/BenchmarkTest/BenchTests/NormalBenchmarkTests.cs b/binding/c#/BenchmarkTest/BenchTests/NormalBenchmarkTests.cs index 40a4175..f3e4fec 100644 --- a/binding/c#/BenchmarkTest/BenchTests/NormalBenchmarkTests.cs +++ b/binding/c#/BenchmarkTest/BenchTests/NormalBenchmarkTests.cs @@ -18,7 +18,7 @@ namespace BenchmarkTest.BenchTests [Benchmark] public async Task TestAsyncSpeedForMemorySearch() { - await _dbSearcher.AsyncMemorySearch(validIp); + await _dbSearcher.MemorySearchAsync(validIp); } [Benchmark] @@ -29,7 +29,7 @@ namespace BenchmarkTest.BenchTests [Benchmark] public async Task TestAsyncBinarySearch() { - await _dbSearcher.AsyncBinarySearch(validIp); + await _dbSearcher.BinarySearchAsync(validIp); } [Benchmark] @@ -40,7 +40,7 @@ namespace BenchmarkTest.BenchTests [Benchmark] public async Task TestAsyncSpeedForBTreeSearch() { - await _dbSearcher.AsyncBtreeSearch(validIp); + await _dbSearcher.BtreeSearchAsync(validIp); } } } diff --git a/binding/c#/BenchmarkTest/BenchmarkTest.csproj b/binding/c#/BenchmarkTest/IP2Region.Test.NetFxBenchmark.csproj similarity index 98% rename from binding/c#/BenchmarkTest/BenchmarkTest.csproj rename to binding/c#/BenchmarkTest/IP2Region.Test.NetFxBenchmark.csproj index c83403a..3145a23 100644 --- a/binding/c#/BenchmarkTest/BenchmarkTest.csproj +++ b/binding/c#/BenchmarkTest/IP2Region.Test.NetFxBenchmark.csproj @@ -1,154 +1,154 @@ - - - - - Debug - AnyCPU - {053EA51E-2246-4FCB-A106-9B53E70FDC3F} - Exe - BenchmarkTest - BenchmarkTest - v4.6 - 512 - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\BenchmarkDotNet.0.10.14\lib\net46\BenchmarkDotNet.dll - - - ..\packages\BenchmarkDotNet.Core.0.10.14\lib\net46\BenchmarkDotNet.Core.dll - - - ..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.10.14\lib\net46\BenchmarkDotNet.Toolchains.Roslyn.dll - - - ..\packages\Microsoft.CodeAnalysis.Common.2.6.1\lib\netstandard1.3\Microsoft.CodeAnalysis.dll - - - ..\packages\Microsoft.CodeAnalysis.CSharp.2.6.1\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll - - - ..\packages\Microsoft.DotNet.InternalAbstractions.1.0.0\lib\net451\Microsoft.DotNet.InternalAbstractions.dll - - - ..\packages\Microsoft.DotNet.PlatformAbstractions.1.1.1\lib\net451\Microsoft.DotNet.PlatformAbstractions.dll - - - ..\packages\Microsoft.Win32.Registry.4.3.0\lib\net46\Microsoft.Win32.Registry.dll - - - - ..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll - - - ..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - - - - ..\packages\System.Console.4.3.0\lib\net46\System.Console.dll - - - - - - ..\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll - - - ..\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll - - - ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll - - - ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll - - - ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll - - - - - - ..\packages\System.Reflection.Metadata.1.4.2\lib\portable-net45+win8\System.Reflection.Metadata.dll - - - ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net46\System.Security.Cryptography.Algorithms.dll - - - ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll - - - ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll - - - ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net46\System.Security.Cryptography.X509Certificates.dll - - - ..\packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll - - - ..\packages\System.Threading.Tasks.Extensions.4.3.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll - - - ..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll - - - ..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll - - - - - ..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll - - - ..\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll - - - ..\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll - - - ..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll - - - - - - - - - - - - - - - - - - - {4c6032ee-43a5-4d5c-88f8-c411069e49e0} - IP2Region - - - + + + + + Debug + AnyCPU + {053EA51E-2246-4FCB-A106-9B53E70FDC3F} + Exe + BenchmarkTest + BenchmarkTest + v4.6 + 512 + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\BenchmarkDotNet.0.10.14\lib\net46\BenchmarkDotNet.dll + + + ..\packages\BenchmarkDotNet.Core.0.10.14\lib\net46\BenchmarkDotNet.Core.dll + + + ..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.10.14\lib\net46\BenchmarkDotNet.Toolchains.Roslyn.dll + + + ..\packages\Microsoft.CodeAnalysis.Common.2.6.1\lib\netstandard1.3\Microsoft.CodeAnalysis.dll + + + ..\packages\Microsoft.CodeAnalysis.CSharp.2.6.1\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll + + + ..\packages\Microsoft.DotNet.InternalAbstractions.1.0.0\lib\net451\Microsoft.DotNet.InternalAbstractions.dll + + + ..\packages\Microsoft.DotNet.PlatformAbstractions.1.1.1\lib\net451\Microsoft.DotNet.PlatformAbstractions.dll + + + ..\packages\Microsoft.Win32.Registry.4.3.0\lib\net46\Microsoft.Win32.Registry.dll + + + + ..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll + + + ..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + + ..\packages\System.Console.4.3.0\lib\net46\System.Console.dll + + + + + + ..\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll + + + ..\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll + + + ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll + + + ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll + + + ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll + + + + + + ..\packages\System.Reflection.Metadata.1.4.2\lib\portable-net45+win8\System.Reflection.Metadata.dll + + + ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net46\System.Security.Cryptography.Algorithms.dll + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net46\System.Security.Cryptography.X509Certificates.dll + + + ..\packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.3.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll + + + ..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll + + + ..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll + + + + + ..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll + + + ..\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll + + + ..\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll + + + ..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll + + + + + + + + + + + + + + + + + + + {4c6032ee-43a5-4d5c-88f8-c411069e49e0} + IP2Region + + + \ No newline at end of file diff --git a/binding/c#/IP2Region.Test.Benchmark/DbSearch_Test.cs b/binding/c#/IP2Region.Test.Benchmark/DbSearch_Test.cs new file mode 100644 index 0000000..5c38760 --- /dev/null +++ b/binding/c#/IP2Region.Test.Benchmark/DbSearch_Test.cs @@ -0,0 +1,59 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Order; +using IP2Region.Models; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace IP2Region.Test.Benchmark +{ + [RankColumn] + public class DbSearch_Test : TestBase + { + private string RandomIP = ""; + + [Benchmark] + public DataBlock MemorySearch() + { + RandomIP = GetRandomIP(); + //Console.WriteLine(RandomIP); + return _search.MemorySearch(RandomIP); + } + + [Benchmark] + public async Task MemorySearch_Async() + { + RandomIP = GetRandomIP(); + return await _search.MemorySearchAsync(RandomIP); + } + + [Benchmark] + public DataBlock BinarySearch() + { + RandomIP = GetRandomIP(); + return _search.BinarySearch(RandomIP); + } + + [Benchmark] + public async Task BinarySearch_Async() + { + RandomIP = GetRandomIP(); + return await _search.BinarySearchAsync(RandomIP); + } + + [Benchmark] + public DataBlock BtreeSearch() + { + RandomIP = GetRandomIP(); + return _search.BtreeSearch(RandomIP); + } + + [Benchmark] + public async Task BtreeSearch_Async() + { + RandomIP = GetRandomIP(); + return await _search.BtreeSearchAsync(RandomIP); + } + } +} diff --git a/binding/c#/IP2Region.Test.Benchmark/IP2Region.Test.Benchmark.csproj b/binding/c#/IP2Region.Test.Benchmark/IP2Region.Test.Benchmark.csproj new file mode 100644 index 0000000..739408f --- /dev/null +++ b/binding/c#/IP2Region.Test.Benchmark/IP2Region.Test.Benchmark.csproj @@ -0,0 +1,16 @@ + + + + Exe + netcoreapp2.0 + + + + + + + + + + + diff --git a/binding/c#/IP2Region.Test.Benchmark/Program.cs b/binding/c#/IP2Region.Test.Benchmark/Program.cs new file mode 100644 index 0000000..3c9d246 --- /dev/null +++ b/binding/c#/IP2Region.Test.Benchmark/Program.cs @@ -0,0 +1,15 @@ +using BenchmarkDotNet.Running; +using System; + +namespace IP2Region.Test.Benchmark +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Welcome To IP2Regin!"); + var summary = BenchmarkRunner.Run(); + Console.ReadLine(); + } + } +} diff --git a/binding/c#/IP2Region.Test.Benchmark/TestBase.cs b/binding/c#/IP2Region.Test.Benchmark/TestBase.cs new file mode 100644 index 0000000..233a33a --- /dev/null +++ b/binding/c#/IP2Region.Test.Benchmark/TestBase.cs @@ -0,0 +1,51 @@ +using BenchmarkDotNet.Attributes; +using System; +using System.Collections.Generic; +using System.Text; + +namespace IP2Region.Test.Benchmark +{ + public class TestBase + { + protected DbSearcher _search; + + private readonly string _dBFilePath = ""; + public TestBase() + { + + } + + public TestBase(String DBFilePath) + { + this._dBFilePath = DBFilePath; + } + + [GlobalSetup] + public void Init() + { + if (String.IsNullOrEmpty(_dBFilePath)) + { + _search = new DbSearcher(AppContext.BaseDirectory + @"\DB\ip2region.db"); + } + else + { + _search = new DbSearcher(_dBFilePath); + } + + } + + [GlobalCleanup] + public void Dispose() + { + _search?.Dispose(); + } + + public String GetRandomIP() + { + return new Random(Guid.NewGuid().GetHashCode()).Next(0, 255).ToString() + "." + + new Random(Guid.NewGuid().GetHashCode()).Next(0, 255).ToString() + "." + + new Random(Guid.NewGuid().GetHashCode()).Next(0, 255).ToString() + "." + + new Random(Guid.NewGuid().GetHashCode()).Next(0, 255).ToString(); + } + } +} diff --git a/binding/c#/IP2Region.Test.xUnit/DB/ip2region.db b/binding/c#/IP2Region.Test.xUnit/DB/ip2region.db new file mode 100644 index 0000000..cc2bef0 Binary files /dev/null and b/binding/c#/IP2Region.Test.xUnit/DB/ip2region.db differ diff --git a/binding/c#/IP2Region.Test.xUnit/IP2Region.Test.xUnit.csproj b/binding/c#/IP2Region.Test.xUnit/IP2Region.Test.xUnit.csproj new file mode 100644 index 0000000..e2b49df --- /dev/null +++ b/binding/c#/IP2Region.Test.xUnit/IP2Region.Test.xUnit.csproj @@ -0,0 +1,26 @@ + + + + netcoreapp2.0 + + false + + + + + + + + + + + + + + + + Always + + + + diff --git a/binding/c#/IP2Region.Test.xUnit/UnitTest1.cs b/binding/c#/IP2Region.Test.xUnit/UnitTest1.cs new file mode 100644 index 0000000..09a6f9b --- /dev/null +++ b/binding/c#/IP2Region.Test.xUnit/UnitTest1.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace IP2Region.Test.xUnit +{ + public class UnitTest1 + { + private readonly DbSearcher _search; + public UnitTest1() + { + _search = new DbSearcher(Environment.CurrentDirectory + @"\DB\ip2region.db"); + } + [Fact] + public void Search_Test() + { + + Assert.NotNull(_search.MemorySearch("183.192.62.65").Region); + Assert.NotNull(_search.MemorySearchAsync("183.192.62.65").Result.Region); + Assert.NotNull(_search.BinarySearch("183.192.62.65").Region); + Assert.NotNull(_search.BinarySearchAsync("183.192.62.65").Result.Region); + Assert.NotNull(_search.BtreeSearch("183.192.62.65").Region); + Assert.NotNull(_search.BtreeSearchAsync("183.192.62.65").Result.Region); + + } + + [Fact] + public async Task SearchAsync_Test() + { + var result = await _search.MemorySearchAsync("183.192.62.65"); + Assert.NotNull(result.Region); + } + + + } +} diff --git a/binding/c#/IP2Region/DB/ip2region.db b/binding/c#/IP2Region/DB/ip2region.db new file mode 100644 index 0000000..cc2bef0 Binary files /dev/null and b/binding/c#/IP2Region/DB/ip2region.db differ diff --git a/binding/c#/IP2Region/DBSearcher.cs b/binding/c#/IP2Region/DBSearcher.cs index 1c1f6d2..80756b3 100644 --- a/binding/c#/IP2Region/DBSearcher.cs +++ b/binding/c#/IP2Region/DBSearcher.cs @@ -1,429 +1,400 @@ -//******************************* -// Create By Rocher Kong -// Github https://github.com/RocherKong -// Date 2018.02.09 -//******************************* +//******************************* +// Created By Rocher Kong +// Github https://github.com/RocherKong +// Date 2018.02.09 +//******************************* + using IP2Region.Models; -using System; -using System.IO; -using System.Text; +using System; +using System.IO; +using System.Text; using System.Threading.Tasks; -namespace IP2Region -{ - public class DbSearcher : IDisposable - { - const int BTREE_ALGORITHM = 1; - const int BINARY_ALGORITHM = 2; - const int MEMORY_ALGORITYM = 3; - - private DbConfig _dbConfig = null; - - /** - * db file access handler - */ - private FileStream _raf = null; - - /** - * header blocks buffer - */ - private long[] _headerSip = null; - private int[] _headerPtr = null; - private int _headerLength; - - /** - * super blocks info - */ - private long _firstIndexPtr = 0; - private long _lastIndexPtr = 0; - private int _totalIndexBlocks = 0; - - /** - * for memory mode - * the original db binary string - */ +namespace IP2Region +{ + public class DbSearcher : IDisposable + { + const int BTREE_ALGORITHM = 1; + const int BINARY_ALGORITHM = 2; + const int MEMORY_ALGORITYM = 3; + + private DbConfig _dbConfig = null; + + /// + /// db file access handler + /// + private FileStream _raf = null; + + /// + /// header blocks buffer + /// + private long[] _headerSip = null; + private int[] _headerPtr = null; + private int _headerLength; + + /// + /// super blocks info + /// + private long _firstIndexPtr = 0; + private long _lastIndexPtr = 0; + private int _totalIndexBlocks = 0; + + /// + /// for memory mode + /// the original db binary string + /// private byte[] _dbBinStr = null; /// /// Get by index ptr. - /// - private DataBlock GetByIndexPtr(long ptr) - { - _raf.Seek(ptr, SeekOrigin.Begin); - byte[] - buffer = new byte[12]; + /// + private DataBlock GetByIndexPtr(long ptr) + { + _raf.Seek(ptr, SeekOrigin.Begin); + byte[] buffer = new byte[12]; _raf.Read(buffer, 0, buffer.Length); + long extra = Utils.GetIntLong(buffer, 8); + int dataLen = (int)((extra >> 24) & 0xFF); + int dataPtr = (int)((extra & 0x00FFFFFF)); + _raf.Seek(dataPtr, SeekOrigin.Begin); + byte[] data = new byte[dataLen]; + _raf.Read(data, 0, data.Length); + int city_id = (int)Utils.GetIntLong(data, 0); + string region = Encoding.UTF8.GetString(data, 4, data.Length - 4); + return new DataBlock(city_id, region, dataPtr); + } - long extra = Utils.getIntLong(buffer, 8); - - int dataLen = (int)((extra >> 24) & 0xFF); - int dataPtr = (int)((extra & 0x00FFFFFF)); - - _raf.Seek(dataPtr, SeekOrigin.Begin); - byte[] data = new byte[dataLen]; - _raf.Read(data, 0, data.Length); - - int city_id = (int)Utils.getIntLong(data, 0); - string region = Encoding.UTF8.GetString(data, 4, data.Length - 4); - - return new DataBlock(city_id, region, dataPtr); - } - - public DbSearcher(DbConfig dbConfig, string dbFile) - { + public DbSearcher(DbConfig dbConfig, string dbFile) + { if (_dbConfig == null) { _dbConfig = dbConfig; - } - _raf = new FileStream(dbFile, FileMode.Open, FileAccess.Read, FileShare.Read); - } - + } + _raf = new FileStream(dbFile, FileMode.Open, FileAccess.Read, FileShare.Read); + } + public DbSearcher(string dbFile) : this(null, dbFile) { } #region Sync Methods /// /// Get the region with a int ip address with memory binary search algorithm. - /// - private DataBlock MemorySearch(long ip) - { - int blen = IndexBlock.LENGTH; - if (_dbBinStr == null) - { - _dbBinStr = new byte[(int)_raf.Length]; - _raf.Seek(0L, SeekOrigin.Begin); - _raf.Read(_dbBinStr, 0, _dbBinStr.Length); - - //initialize the global vars - _firstIndexPtr = Utils.getIntLong(_dbBinStr, 0); - _lastIndexPtr = Utils.getIntLong(_dbBinStr, 4); - _totalIndexBlocks = (int)((_lastIndexPtr - _firstIndexPtr) / blen) + 1; - } - - //search the index blocks to define the data - int l = 0, h = _totalIndexBlocks; - long sip = 0; - - while (l <= h) - { - int m = (l + h) >> 1; - int p = (int)(_firstIndexPtr + m * blen); - - sip = Utils.getIntLong(_dbBinStr, p); - - if (ip < sip) - { - h = m - 1; - } - else - { - sip = Utils.getIntLong(_dbBinStr, p + 4); - if (ip > sip) - { - l = m + 1; - } - else - { - sip = Utils.getIntLong(_dbBinStr, p + 8); - break; - } - } - } - - //not matched - if (sip == 0) return null; - - //get the data - int dataLen = (int)((sip >> 24) & 0xFF); - int dataPtr = (int)((sip & 0x00FFFFFF)); - int city_id = (int)Utils.getIntLong(_dbBinStr, dataPtr); - string region = Encoding.UTF8.GetString(_dbBinStr, dataPtr + 4, dataLen - 4);//new String(dbBinStr, dataPtr + 4, dataLen - 4, Encoding.UTF8); - - return new DataBlock(city_id, region, dataPtr); - } - + /// + private DataBlock MemorySearch(long ip) + { + int blen = IndexBlock.LENGTH; + if (_dbBinStr == null) + { + _dbBinStr = new byte[(int)_raf.Length]; + _raf.Seek(0L, SeekOrigin.Begin); + _raf.Read(_dbBinStr, 0, _dbBinStr.Length); + + //initialize the global vars + _firstIndexPtr = Utils.GetIntLong(_dbBinStr, 0); + _lastIndexPtr = Utils.GetIntLong(_dbBinStr, 4); + _totalIndexBlocks = (int)((_lastIndexPtr - _firstIndexPtr) / blen) + 1; + } + + //search the index blocks to define the data + int l = 0, h = _totalIndexBlocks; + long sip = 0; + + while (l <= h) + { + int m = (l + h) >> 1; + int p = (int)(_firstIndexPtr + m * blen); + + sip = Utils.GetIntLong(_dbBinStr, p); + + if (ip < sip) + { + h = m - 1; + } + else + { + sip = Utils.GetIntLong(_dbBinStr, p + 4); + if (ip > sip) + { + l = m + 1; + } + else + { + sip = Utils.GetIntLong(_dbBinStr, p + 8); + break; + } + } + } + + //not matched + if (sip == 0) return null; + + //get the data + int dataLen = (int)((sip >> 24) & 0xFF); + int dataPtr = (int)((sip & 0x00FFFFFF)); + int city_id = (int)Utils.GetIntLong(_dbBinStr, dataPtr); + string region = Encoding.UTF8.GetString(_dbBinStr, dataPtr + 4, dataLen - 4);//new String(dbBinStr, dataPtr + 4, dataLen - 4, Encoding.UTF8); + + return new DataBlock(city_id, region, dataPtr); + } + /// /// Get the region throught the ip address with memory binary search algorithm. - /// - public DataBlock MemorySearch(string ip) - { - return MemorySearch(Utils.ip2long(ip)); - } - + /// + public DataBlock MemorySearch(string ip) + { + return MemorySearch(Utils.Ip2long(ip)); + } + /// /// Get the region with a int ip address with b-tree algorithm. - /// - private DataBlock BtreeSearch(long ip) - { - //check and load the header - if (_headerSip == null) - { + /// + private DataBlock BtreeSearch(long ip) + { + //check and load the header + if (_headerSip == null) + { _raf.Seek(8L, SeekOrigin.Begin); //pass the super block - //byte[] b = new byte[dbConfig.getTotalHeaderSize()]; - byte[] b = new byte[4096]; - _raf.Read(b, 0, b.Length); - - //fill the header - int len = b.Length >> 3, idx = 0; //b.lenght / 8 - _headerSip = new long[len]; - _headerPtr = new int[len]; - long startIp, dataPtrTemp; - for (int i = 0; i < b.Length; i += 8) - { - startIp = Utils.getIntLong(b, i); - dataPtrTemp = Utils.getIntLong(b, i + 4); - if (dataPtrTemp == 0) break; - - _headerSip[idx] = startIp; - _headerPtr[idx] = (int)dataPtrTemp; - idx++; - } - - _headerLength = idx; - } - - //1. define the index block with the binary search - if (ip == _headerSip[0]) - { - return GetByIndexPtr(_headerPtr[0]); - } - else if (ip == _headerPtr[_headerLength - 1]) - { - return GetByIndexPtr(_headerPtr[_headerLength - 1]); - } - - int l = 0, h = _headerLength, sptr = 0, eptr = 0; - int m = 0; - - while (l <= h) - { - m = (l + h) >> 1; - - //perfectly matched, just return it - if (ip == _headerSip[m]) - { - if (m > 0) - { - sptr = _headerPtr[m - 1]; - eptr = _headerPtr[m]; - } - else - { - sptr = _headerPtr[m]; - eptr = _headerPtr[m + 1]; - } - } - //less then the middle value - else if (ip < _headerSip[m]) - { - if (m == 0) - { - sptr = _headerPtr[m]; - eptr = _headerPtr[m + 1]; - break; - } - else if (ip > _headerSip[m - 1]) - { - sptr = _headerPtr[m - 1]; - eptr = _headerPtr[m]; - break; - } - h = m - 1; - } - else - { - if (m == _headerLength - 1) - { - sptr = _headerPtr[m - 1]; - eptr = _headerPtr[m]; - break; - } - else if (ip <= _headerSip[m + 1]) - { - sptr = _headerPtr[m]; - eptr = _headerPtr[m + 1]; - break; - } - l = m + 1; - } - } - - //match nothing just stop it - if (sptr == 0) return null; - - //2. search the index blocks to define the data - int blockLen = eptr - sptr, blen = IndexBlock.LENGTH; - byte[] iBuffer = new byte[blockLen + blen]; //include the right border block - _raf.Seek(sptr, SeekOrigin.Begin); - _raf.Read(iBuffer, 0, iBuffer.Length); - - l = 0; h = blockLen / blen; - long sip = 0; - int p = 0; - - while (l <= h) - { - m = (l + h) >> 1; - p = m * blen; - sip = Utils.getIntLong(iBuffer, p); - if (ip < sip) - { - h = m - 1; - } - else - { - sip = Utils.getIntLong(iBuffer, p + 4); - if (ip > sip) - { - l = m + 1; - } - else - { - sip = Utils.getIntLong(iBuffer, p + 8); - break; - } - } - } - - //not matched - if (sip == 0) return null; - - //3. get the data - int dataLen = (int)((sip >> 24) & 0xFF); - int dataPtr = (int)((sip & 0x00FFFFFF)); - - _raf.Seek(dataPtr, SeekOrigin.Begin); - byte[] data = new byte[dataLen]; - _raf.Read(data, 0, data.Length); - - int city_id = (int)Utils.getIntLong(data, 0); - String region = Encoding.UTF8.GetString(data, 4, data.Length - 4);// new String(data, 4, data.Length - 4, "UTF-8"); - - return new DataBlock(city_id, region, dataPtr); - } - + byte[] b = new byte[4096]; + _raf.Read(b, 0, b.Length); + //fill the header + int len = b.Length >> 3, idx = 0; //b.lenght / 8 + _headerSip = new long[len]; + _headerPtr = new int[len]; + long startIp, dataPtrTemp; + for (int i = 0; i < b.Length; i += 8) + { + startIp = Utils.GetIntLong(b, i); + dataPtrTemp = Utils.GetIntLong(b, i + 4); + if (dataPtrTemp == 0) break; + + _headerSip[idx] = startIp; + _headerPtr[idx] = (int)dataPtrTemp; + idx++; + } + _headerLength = idx; + } + + //1. define the index block with the binary search + if (ip == _headerSip[0]) + { + return GetByIndexPtr(_headerPtr[0]); + } + else if (ip == _headerPtr[_headerLength - 1]) + { + return GetByIndexPtr(_headerPtr[_headerLength - 1]); + } + int l = 0, h = _headerLength, sptr = 0, eptr = 0; + int m = 0; + while (l <= h) + { + m = (l + h) >> 1; + //perfectly matched, just return it + if (ip == _headerSip[m]) + { + if (m > 0) + { + sptr = _headerPtr[m - 1]; + eptr = _headerPtr[m]; + } + else + { + sptr = _headerPtr[m]; + eptr = _headerPtr[m + 1]; + } + } + //less then the middle value + else if (ip < _headerSip[m]) + { + if (m == 0) + { + sptr = _headerPtr[m]; + eptr = _headerPtr[m + 1]; + break; + } + else if (ip > _headerSip[m - 1]) + { + sptr = _headerPtr[m - 1]; + eptr = _headerPtr[m]; + break; + } + h = m - 1; + } + else + { + if (m == _headerLength - 1) + { + sptr = _headerPtr[m - 1]; + eptr = _headerPtr[m]; + break; + } + else if (ip <= _headerSip[m + 1]) + { + sptr = _headerPtr[m]; + eptr = _headerPtr[m + 1]; + break; + } + l = m + 1; + } + } + //match nothing just stop it + if (sptr == 0) return null; + //2. search the index blocks to define the data + int blockLen = eptr - sptr, blen = IndexBlock.LENGTH; + byte[] iBuffer = new byte[blockLen + blen]; //include the right border block + _raf.Seek(sptr, SeekOrigin.Begin); + _raf.Read(iBuffer, 0, iBuffer.Length); + l = 0; h = blockLen / blen; + long sip = 0; + int p = 0; + while (l <= h) + { + m = (l + h) >> 1; + p = m * blen; + sip = Utils.GetIntLong(iBuffer, p); + if (ip < sip) + { + h = m - 1; + } + else + { + sip = Utils.GetIntLong(iBuffer, p + 4); + if (ip > sip) + { + l = m + 1; + } + else + { + sip = Utils.GetIntLong(iBuffer, p + 8); + break; + } + } + } + //not matched + if (sip == 0) return null; + //3. get the data + int dataLen = (int)((sip >> 24) & 0xFF); + int dataPtr = (int)((sip & 0x00FFFFFF)); + _raf.Seek(dataPtr, SeekOrigin.Begin); + byte[] data = new byte[dataLen]; + _raf.Read(data, 0, data.Length); + int city_id = (int)Utils.GetIntLong(data, 0); + String region = Encoding.UTF8.GetString(data, 4, data.Length - 4);// new String(data, 4, data.Length - 4, "UTF-8"); + return new DataBlock(city_id, region, dataPtr); + } + /// /// Get the region throught the ip address with b-tree search algorithm. - /// - public DataBlock BtreeSearch(string ip) - { - return BtreeSearch(Utils.ip2long(ip)); - } - + /// + public DataBlock BtreeSearch(string ip) + { + return BtreeSearch(Utils.Ip2long(ip)); + } + /// /// Get the region with a int ip address with binary search algorithm. - /// - private DataBlock BinarySearch(long ip) - { - int blen = IndexBlock.LENGTH; - if (_totalIndexBlocks == 0) - { - _raf.Seek(0L, SeekOrigin.Begin); - byte[] superBytes = new byte[8]; - _raf.Read(superBytes, 0, superBytes.Length); - //initialize the global vars - _firstIndexPtr = Utils.getIntLong(superBytes, 0); - _lastIndexPtr = Utils.getIntLong(superBytes, 4); - _totalIndexBlocks = (int)((_lastIndexPtr - _firstIndexPtr) / blen) + 1; - } - - //search the index blocks to define the data - int l = 0, h = _totalIndexBlocks; - byte[] buffer = new byte[blen]; - long sip = 0; - - while (l <= h) - { - int m = (l + h) >> 1; - _raf.Seek(_firstIndexPtr + m * blen, SeekOrigin.Begin); //set the file pointer - _raf.Read(buffer, 0, buffer.Length); - sip = Utils.getIntLong(buffer, 0); - if (ip < sip) - { - h = m - 1; - } - else - { - sip = Utils.getIntLong(buffer, 4); - if (ip > sip) - { - l = m + 1; - } - else - { - sip = Utils.getIntLong(buffer, 8); - break; - } - } - } - - //not matched - if (sip == 0) return null; - - //get the data - int dataLen = (int)((sip >> 24) & 0xFF); - int dataPtr = (int)((sip & 0x00FFFFFF)); - - _raf.Seek(dataPtr, SeekOrigin.Begin); - byte[] data = new byte[dataLen]; - _raf.Read(data, 0, data.Length); + /// + private DataBlock BinarySearch(long ip) + { + int blen = IndexBlock.LENGTH; + if (_totalIndexBlocks == 0) + { + _raf.Seek(0L, SeekOrigin.Begin); + byte[] superBytes = new byte[8]; + _raf.Read(superBytes, 0, superBytes.Length); + //initialize the global vars + _firstIndexPtr = Utils.GetIntLong(superBytes, 0); + _lastIndexPtr = Utils.GetIntLong(superBytes, 4); + _totalIndexBlocks = (int)((_lastIndexPtr - _firstIndexPtr) / blen) + 1; + } - int city_id = (int)Utils.getIntLong(data, 0); - String region = Encoding.UTF8.GetString(data, 4, data.Length - 4);//new String(data, 4, data.Length - 4, "UTF-8"); - - return new DataBlock(city_id, region, dataPtr); + //search the index blocks to define the data + int l = 0, h = _totalIndexBlocks; + byte[] buffer = new byte[blen]; + long sip = 0; + while (l <= h) + { + int m = (l + h) >> 1; + _raf.Seek(_firstIndexPtr + m * blen, SeekOrigin.Begin); //set the file pointer + _raf.Read(buffer, 0, buffer.Length); + sip = Utils.GetIntLong(buffer, 0); + if (ip < sip) + { + h = m - 1; + } + else + { + sip = Utils.GetIntLong(buffer, 4); + if (ip > sip) + { + l = m + 1; + } + else + { + sip = Utils.GetIntLong(buffer, 8); + break; + } + } + } + //not matched + if (sip == 0) return null; + //get the data + int dataLen = (int)((sip >> 24) & 0xFF); + int dataPtr = (int)((sip & 0x00FFFFFF)); + _raf.Seek(dataPtr, SeekOrigin.Begin); + byte[] data = new byte[dataLen]; + _raf.Read(data, 0, data.Length); + int city_id = (int)Utils.GetIntLong(data, 0); + String region = Encoding.UTF8.GetString(data, 4, data.Length - 4);//new String(data, 4, data.Length - 4, "UTF-8"); + return new DataBlock(city_id, region, dataPtr); } /// /// Get the region throught the ip address with binary search algorithm. - /// - public DataBlock BinarySearch(String ip) - { - return BinarySearch(Utils.ip2long(ip)); + /// + public DataBlock BinarySearch(String ip) + { + return BinarySearch(Utils.Ip2long(ip)); } - #endregion - #region Async Methods - + #region Async Methods /// /// Get the region throught the ip address with memory binary search algorithm. - /// - public async Task AsyncMemorySearch(string ip) - { - return await Task.FromResult(MemorySearch(ip)); - } + /// + public async Task MemorySearchAsync(string ip) + { + return await Task.FromResult(MemorySearch(ip)); + } /// /// Get the region throught the ip address with b-tree search algorithm. - /// - public async Task AsyncBtreeSearch(string ip) - { - return await Task.FromResult(BtreeSearch(ip)); + /// + public async Task BtreeSearchAsync(string ip) + { + return await Task.FromResult(BtreeSearch(ip)); } - /// /// Get the region throught the ip address with binary search algorithm. - /// - public async Task AsyncBinarySearch(string ip) - { - return await Task.FromResult(BinarySearch(ip)); + /// + public async Task BinarySearchAsync(string ip) + { + return await Task.FromResult(BinarySearch(ip)); } - #endregion + /// /// Close the db. - /// - public void Close() - { - _headerSip = null; //let gc do its work - _headerPtr = null; - _dbBinStr = null; - _raf.Close(); + /// + public void Close() + { + _headerSip = null; + _headerPtr = null; + _dbBinStr = null; + _raf.Close(); } public void Dispose() { Close(); - } - } - + } + } + } \ No newline at end of file diff --git a/binding/c#/IP2Region/IP2Region.csproj b/binding/c#/IP2Region/IP2Region.csproj index 7219992..cd44bf1 100644 --- a/binding/c#/IP2Region/IP2Region.csproj +++ b/binding/c#/IP2Region/IP2Region.csproj @@ -1,26 +1,26 @@ - - - - netstandard2.0;net46 - true - Rocher - Rocher - 准确率99.9%的ip地址定位库,0.0x毫秒级查询, 支持Binary,B树,内存三种查询算法,妈妈再也不用担心我的ip地址定位! - ip2region - 最自由的ip地址查询库,ip到地区的映射库,提供Binary,B树和纯内存三种查询算法,妈妈再也不用担心我的ip地址定位。 - Rocher - ip2region c# IP - https://gitee.com/rocherkong/IP2Region - 1.1.0 - - + + + + netstandard2.0;net46;net45;net47 + true + Rocher + Rocher + 准确率99.9%的ip地址定位库,0.0x毫秒级查询, 支持Binary,B树,内存三种查询算法,妈妈再也不用担心我的ip地址定位! + ip2region - 最自由的ip地址查询库,ip到地区的映射库,提供Binary,B树和纯内存三种查询算法,妈妈再也不用担心我的ip地址定位。 + Rocher + ip2region c# IP + https://gitee.com/rocherkong/IP2Region + 1.2.0 + + 7 - - - - - Always - - - - + + + + + Always + + + + diff --git a/binding/c#/IP2Region/Models/DataBlock.cs b/binding/c#/IP2Region/Models/DataBlock.cs index db6b19a..273d8f7 100644 --- a/binding/c#/IP2Region/Models/DataBlock.cs +++ b/binding/c#/IP2Region/Models/DataBlock.cs @@ -1,55 +1,50 @@ -//******************************* -// Create By Rocher Kong -// Github https://github.com/RocherKong -// Date 2018.02.09 -// -// Modified By Dongwei -// Date 2018.07.18 -// GitHub https://github.com/Maledong -//******************************* - -namespace IP2Region.Models -{ - public class DataBlock +//******************************* +// Created By Rocher Kong +// Github https://github.com/RocherKong +// Date 2018.02.09 +//******************************* +namespace IP2Region.Models +{ + public class DataBlock { - #region Private Properties + #region Private Properties public int CityID { get; private set; - } - + } + public string Region { get; private set; - } - + } + public int DataPtr { get; private set; } - #endregion + #endregion - #region Constructor - public DataBlock(int city_id, string region, int dataPtr = 0) - { - CityID = city_id; - Region = region; - DataPtr = dataPtr; - } - - public DataBlock(int city_id, string region):this(city_id,region,0) - { + #region Constructor + public DataBlock(int city_id, string region, int dataPtr = 0) + { + CityID = city_id; + Region = region; + DataPtr = dataPtr; } - #endregion - - public override string ToString() - { - return $"{CityID}|{Region}|{DataPtr}"; - } - - } - -} + + public DataBlock(int city_id, string region):this(city_id,region,0) + { + } + #endregion + + public override string ToString() + { + return $"{CityID}|{Region}|{DataPtr}"; + } + + } + +} diff --git a/binding/c#/IP2Region/Models/DbConfig.cs b/binding/c#/IP2Region/Models/DbConfig.cs index d823d34..b98d121 100644 --- a/binding/c#/IP2Region/Models/DbConfig.cs +++ b/binding/c#/IP2Region/Models/DbConfig.cs @@ -1,54 +1,49 @@ -//******************************* -// Create By Rocher Kong -// Github https://github.com/RocherKong -// Date 2018.02.09 -// -// Modified By Dongwei -// Date 2018.07.18 -// GitHub https://github.com/Maledong -//******************************* - +//******************************* +// Created By Rocher Kong +// Github https://github.com/RocherKong +// Date 2018.02.09 +//******************************* using System; -namespace IP2Region.Models -{ - public class DbMakerConfigException : Exception - { - public string ErrMsg { get; private set; } - public DbMakerConfigException(string errMsg) +namespace IP2Region.Models +{ + public class DbMakerConfigException : Exception + { + public string ErrMsg { get; private set; } + public DbMakerConfigException(string errMsg) { - ErrMsg = errMsg; - } - } - - public class DbConfig - { + ErrMsg = errMsg; + } + } + + public class DbConfig + { public int TotalHeaderSize { get; private set; - } - + } + public int indexBlockSize { get; private set; - } - - public DbConfig(int totalHeaderSize) - { - if ((totalHeaderSize % 8) != 0) - { - throw new DbMakerConfigException("totalHeaderSize must be times of 8"); - } - TotalHeaderSize = totalHeaderSize; - //4 * 2048 - indexBlockSize = 8192; - } - - public DbConfig():this(8 * 2048) - { - } - } - + } + + public DbConfig(int totalHeaderSize) + { + if ((totalHeaderSize % 8) != 0) + { + throw new DbMakerConfigException("totalHeaderSize must be times of 8"); + } + TotalHeaderSize = totalHeaderSize; + //4 * 2048 + indexBlockSize = 8192; + } + + public DbConfig():this(8 * 2048) + { + } + } + } \ No newline at end of file diff --git a/binding/c#/IP2Region/Models/HeaderBlock.cs b/binding/c#/IP2Region/Models/HeaderBlock.cs index 24de495..791227d 100644 --- a/binding/c#/IP2Region/Models/HeaderBlock.cs +++ b/binding/c#/IP2Region/Models/HeaderBlock.cs @@ -1,56 +1,49 @@ -//******************************* -// Create By Rocher Kong -// Github https://github.com/RocherKong -// Date 2018.02.09 -// -// Modified By Dongwei -// Date 2018.07.18 -// GitHub https://github.com/Maledong -//******************************* - - -namespace IP2Region.Models -{ - internal class HeaderBlock - { +//******************************* +// Created By Rocher Kong +// Github https://github.com/RocherKong +// Date 2018.02.09 +//******************************* + +namespace IP2Region.Models +{ + internal class HeaderBlock + { public long IndexStartIp { get; private set; - } - + } + public int IndexPtr { get; private set; - } - - public HeaderBlock(long indexStartIp, int indexPtr) + } + + public HeaderBlock(long indexStartIp, int indexPtr) { IndexStartIp = indexStartIp; - IndexPtr = indexPtr; - } - - /// - /// Get the bytes for total storage - /// - /// - /// Bytes gotten. - /// - public byte[] GetBytes() - { - /* - * +------------+-----------+ - * | 4bytes | 4bytes | - * +------------+-----------+ - * start ip index ptr - */ - byte[] b = new byte[8]; - - Utils.writeIntLong(b, 0, IndexStartIp); - Utils.writeIntLong(b, 4, IndexPtr); - - return b; - } - } + IndexPtr = indexPtr; + } + + /// + /// Get the bytes for total storage + /// + /// + /// Bytes gotten. + /// + public byte[] GetBytes() + { + /* + * +------------+-----------+ + * | 4bytes | 4bytes | + * +------------+-----------+ + * start ip index ptr + */ + byte[] b = new byte[8]; + Utils.WriteIntLong(b, 0, IndexStartIp); + Utils.WriteIntLong(b, 4, IndexPtr); + return b; + } + } } \ No newline at end of file diff --git a/binding/c#/IP2Region/Models/IndexBlock.cs b/binding/c#/IP2Region/Models/IndexBlock.cs index ce0679e..417c5f0 100644 --- a/binding/c#/IP2Region/Models/IndexBlock.cs +++ b/binding/c#/IP2Region/Models/IndexBlock.cs @@ -1,69 +1,65 @@ -//******************************* -// Create By Rocher Kong -// Github https://github.com/RocherKong -// Date 2018.02.09 -// -// Modified By Dongwei -// Date 2018.07.18 -// GitHub https://github.com/Maledong -//******************************* - -namespace IP2Region -{ - internal class IndexBlock - { - public const int LENGTH = 12; - +//******************************* +// Created By Rocher Kong +// Github https://github.com/RocherKong +// Date 2018.02.09 +//******************************* + +namespace IP2Region +{ + internal class IndexBlock + { + public const int LENGTH = 12; + public long StartIP { get; private set; - } - + } + public long EndIp { get; private set; - } - + } + public uint DataPtr { get; private set; - } - + } + public int DataLen { get; private set; - } - - public IndexBlock(long startIp, long endIp, uint dataPtr, int dataLen) - { - StartIP = startIp; - EndIp = endIp; - DataPtr = dataPtr; - DataLen = dataLen; - } - - public byte[] GetBytes() - { - /* - * +------------+-----------+-----------+ - * | 4bytes | 4bytes | 4bytes | - * +------------+-----------+-----------+ - * start ip end ip data ptr + len - */ - byte[] b = new byte[12]; - - Utils.writeIntLong(b, 0, StartIP); //start ip - Utils.writeIntLong(b, 4, EndIp); //end ip - - //write the data ptr and the length - long mix = DataPtr | ((DataLen << 24) & 0xFF000000L); - Utils.writeIntLong(b, 8, mix); - - return b; - } - } + } + + public IndexBlock(long startIp, long endIp, uint dataPtr, int dataLen) + { + StartIP = startIp; + EndIp = endIp; + DataPtr = dataPtr; + DataLen = dataLen; + } + + public byte[] GetBytes() + { + /* + * +------------+-----------+-----------+ + * | 4bytes | 4bytes | 4bytes | + * +------------+-----------+-----------+ + * start ip end ip data ptr + len + */ + byte[] b = new byte[12]; + + Utils.WriteIntLong(b, 0, StartIP); //start ip + Utils.WriteIntLong(b, 4, EndIp); //end ip + + //write the data ptr and the length + long mix = DataPtr | ((DataLen << 24) & 0xFF000000L); + Utils.WriteIntLong(b, 8, mix); + + return b; + } + } } \ No newline at end of file diff --git a/binding/c#/IP2Region/Utils.cs b/binding/c#/IP2Region/Utils.cs index 9d6d881..20f42aa 100644 --- a/binding/c#/IP2Region/Utils.cs +++ b/binding/c#/IP2Region/Utils.cs @@ -1,130 +1,122 @@ -//******************************* -// Create By Rocher Kong -// Github https://github.com/RocherKong -// Date 2018.02.09 -// -// Modified By Dongwei -// Date 2018.07.18 -// GitHub https://github.com/Maledong -//******************************* -using System; - -namespace IP2Region -{ +//******************************* +// Created By Rocher Kong +// Github https://github.com/RocherKong +// Date 2018.02.09 +//******************************* + +using System; + +namespace IP2Region +{ public class IPInValidException : Exception { const string ERROR_MSG = "IP Illigel. Please input a valid IP."; - public IPInValidException() : base(ERROR_MSG) { } - } - internal static class Utils - { + } + internal static class Utils + { /// /// Write specfield bytes to a byte array start from offset. - /// - public static void Write(byte[] b, int offset, ulong v, int bytes) - { - for (int i = 0; i < bytes; i++) - { - b[offset++] = (byte)((v >> (8 * i)) & 0xFF); - } + /// + public static void Write(byte[] b, int offset, ulong v, int bytes) + { + for (int i = 0; i < bytes; i++) + { + b[offset++] = (byte)((v >> (8 * i)) & 0xFF); + } } /// /// Write a int to a byte array. - /// - public static void writeIntLong(byte[] b, int offset, long v) - { - b[offset++] = (byte)((v >> 0) & 0xFF); - b[offset++] = (byte)((v >> 8) & 0xFF); - b[offset++] = (byte)((v >> 16) & 0xFF); - b[offset] = (byte)((v >> 24) & 0xFF); + /// + public static void WriteIntLong(byte[] b, int offset, long v) + { + b[offset++] = (byte)((v >> 0) & 0xFF); + b[offset++] = (byte)((v >> 8) & 0xFF); + b[offset++] = (byte)((v >> 16) & 0xFF); + b[offset] = (byte)((v >> 24) & 0xFF); } /// /// Get a int from a byte array start from the specifiled offset. - /// - public static long getIntLong(byte[] b, int offset) - { - return ( - ((b[offset++] & 0x000000FFL)) | - ((b[offset++] << 8) & 0x0000FF00L) | - ((b[offset++] << 16) & 0x00FF0000L) | - ((b[offset] << 24) & 0xFF000000L) - ); - } - + /// + public static long GetIntLong(byte[] b, int offset) + { + return ( + ((b[offset++] & 0x000000FFL)) | + ((b[offset++] << 8) & 0x0000FF00L) | + ((b[offset++] << 16) & 0x00FF0000L) | + ((b[offset] << 24) & 0xFF000000L) + ); + } + /// /// Get a int from a byte array start from the specifield offset. - /// - public static int getInt3(byte[] b, int offset) - { - return ( - (b[offset++] & 0x000000FF) | - (b[offset++] & 0x0000FF00) | - (b[offset] & 0x00FF0000) - ); - } - - public static int getInt2(byte[] b, int offset) - { - return ( - (b[offset++] & 0x000000FF) | - (b[offset] & 0x0000FF00) - ); - } - - public static int getInt1(byte[] b, int offset) - { - return ( - (b[offset] & 0x000000FF) - ); - } - + /// + public static int GetInt3(byte[] b, int offset) + { + return ( + (b[offset++] & 0x000000FF) | + (b[offset++] & 0x0000FF00) | + (b[offset] & 0x00FF0000) + ); + } + + public static int GetInt2(byte[] b, int offset) + { + return ( + (b[offset++] & 0x000000FF) | + (b[offset] & 0x0000FF00) + ); + } + + public static int GetInt1(byte[] b, int offset) + { + return ( + (b[offset] & 0x000000FF) + ); + } /// /// String ip to long ip. - /// - public static long ip2long(string ip) + /// + public static long Ip2long(string ip) { - string[] p = ip.Split('.'); - if (p.Length != 4) throw new IPInValidException(); - - foreach (string pp in p) - { + string[] p = ip.Split('.'); + if (p.Length != 4) throw new IPInValidException(); + + foreach (string pp in p) + { if (pp.Length > 3) throw new IPInValidException(); if (!int.TryParse(pp, out int value) || value > 255) { throw new IPInValidException(); - } + } } - - var bip1 = long.TryParse(p[0], out long ip1); - var bip2 = long.TryParse(p[1], out long ip2); - var bip3 = long.TryParse(p[2], out long ip3); - var bip4 = long.TryParse(p[3], out long ip4); - - if (!bip1 || !bip2 || !bip3 || !bip4 - || ip4 > 255 || ip1 > 255 || ip2 > 255 || ip3 > 255 - || ip4 < 0 || ip1 < 0 || ip2 < 0 || ip3 < 0) - { - throw new IPInValidException(); + var bip1 = long.TryParse(p[0], out long ip1); + var bip2 = long.TryParse(p[1], out long ip2); + var bip3 = long.TryParse(p[2], out long ip3); + var bip4 = long.TryParse(p[3], out long ip4); + + if (!bip1 || !bip2 || !bip3 || !bip4 + || ip4 > 255 || ip1 > 255 || ip2 > 255 || ip3 > 255 + || ip4 < 0 || ip1 < 0 || ip2 < 0 || ip3 < 0) + { + throw new IPInValidException(); } - - - long p1 = ((ip1 << 24) & 0xFF000000); - long p2 = ((ip2 << 16) & 0x00FF0000); - long p3 = ((ip3 << 8) & 0x0000FF00); - long p4 = ((ip4 << 0) & 0x000000FF); - return ((p1 | p2 | p3 | p4) & 0xFFFFFFFFL); + long p1 = ((ip1 << 24) & 0xFF000000); + long p2 = ((ip2 << 16) & 0x00FF0000); + long p3 = ((ip3 << 8) & 0x0000FF00); + long p4 = ((ip4 << 0) & 0x000000FF); + return ((p1 | p2 | p3 | p4) & 0xFFFFFFFFL); } /// /// Int to ip string. - /// - public static string long2ip(long ip) - { - return $"{(ip >> 24) & 0xFF}.{(ip >> 16) & 0xFF}.{(ip >> 8) & 0xFF}.{ip & 0xFF}"; - } - } - + /// + public static string Long2ip(long ip) + { + return $"{(ip >> 24) & 0xFF}.{(ip >> 16) & 0xFF}.{(ip >> 8) & 0xFF}.{ip & 0xFF}"; + } + } + } \ No newline at end of file diff --git a/binding/c#/IP2Region_NetFx_Test/App.config b/binding/c#/IP2Region_NetFx_Test/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/binding/c#/IP2Region_NetFx_Test/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/binding/c#/IP2Region_NetFx_Test/DB/ip2region.db b/binding/c#/IP2Region_NetFx_Test/DB/ip2region.db new file mode 100644 index 0000000..cc2bef0 Binary files /dev/null and b/binding/c#/IP2Region_NetFx_Test/DB/ip2region.db differ diff --git a/binding/c#/IP2Region_NetFx_Test/IP2Region_NetFx_Test.csproj b/binding/c#/IP2Region_NetFx_Test/IP2Region_NetFx_Test.csproj new file mode 100644 index 0000000..bc5f799 --- /dev/null +++ b/binding/c#/IP2Region_NetFx_Test/IP2Region_NetFx_Test.csproj @@ -0,0 +1,60 @@ + + + + + Debug + AnyCPU + {2D73D7EB-AE36-4039-A839-DA40209052A4} + Exe + IP2Region_NetFx_Test + IP2Region_NetFx_Test + v4.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + Always + + + + + {a27d09f4-4da8-4925-90ec-43e5f5288630} + IP2Region + + + + \ No newline at end of file diff --git a/binding/c#/IP2Region_NetFx_Test/Program.cs b/binding/c#/IP2Region_NetFx_Test/Program.cs new file mode 100644 index 0000000..f0de3e1 --- /dev/null +++ b/binding/c#/IP2Region_NetFx_Test/Program.cs @@ -0,0 +1,19 @@ +using IP2Region; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IP2Region_NetFx_Test +{ + class Program + { + static void Main(string[] args) + { + DbSearcher _search = new DbSearcher(Environment.CurrentDirectory + @"\DB\ip2region.db"); + Console.WriteLine(_search.MemorySearch("183.192.62.65").Region); + Console.Read(); + } + } +} diff --git a/binding/c#/IP2Region_NetFx_Test/Properties/AssemblyInfo.cs b/binding/c#/IP2Region_NetFx_Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..92c2b2d --- /dev/null +++ b/binding/c#/IP2Region_NetFx_Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("IP2Region_NetFx_Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("IP2Region_NetFx_Test")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("2d73d7eb-ae36-4039-a839-da40209052a4")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 +// 方法是按如下所示使用“*”: : +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/binding/c#/README.md b/binding/c#/README.md index e455346..f7f22ab 100644 --- a/binding/c#/README.md +++ b/binding/c#/README.md @@ -1,18 +1,38 @@ -# C# 客户端 +# IP2Region C# Client -## 实现情况: +## How To Use +### 1.Install from Nuget. Support .Net Framework 4.5+ And netstandard 2.0(.net core) +```powershell +Install-Package IP2Region +``` +### 2.Init DbSearcher with Newest DBFile Downloaded into your project.(https://github.com/lionsoul2014/ip2region/blob/master/data/ip2region.db) +```c# +DbSearcher _search=new DbSearcher(Environment.CurrentDirectory + @"\DB\ip2region.db"); +``` +### 3.Invoke Search Method.(MemorySearch,BtreeSearch,BinarySearch) +```c# + _search.MemorySearch("183.192.62.65").Region; + _search.MemorySearchAsync("183.192.62.65").Result.Region; + _search.BinarySearch("183.192.62.65").Region; + _search.BinarySearchAsync("183.192.62.65").Result.Region; + _search.BtreeSearch("183.192.62.65").Region; + _search.BtreeSearchAsync("183.192.62.65").Result.Region; +``` -现已实现同步和异步查询,具体使用方法可以参考 UnitTests 中的使用方法。 +## Test Result(From /IP2Region.Test.Benchmark) + Method | Mean | Error | StdDev | Rank | +------------------- |---------: |----------: |----------: |-----: | +MemorySearch | 10.66 us | 0.1424 us | 0.1332 us | 1 | +MemorySearch_Async | 10.90 us | 0.2060 us | 0.2023 us | 2 | +BinarySearch | 52.22 us | 0.6403 us | 0.5347 us | 5 | +BinarySearch_Async | 53.03 us | 1.0271 us | 0.9608 us | 6 | +BtreeSearch | 19.05 us | 0.2464 us | 0.2305 us | 3 | +BtreeSearch_Async | 19.40 us | 0.3820 us | 0.6690 us | 4 | -## 如何贡献? +## Contribute History +| Name | Github | Responsibility | Date | Remark | +| ------ | ------ | ------ | ------ | ------ | +| RocherKong | https://github.com/RocherKong | Creator | 20180209| +| Dongwei | https://github.com/Maledong | Contributor | 20180708 | 1.Async 2.NetFxBenchmark 3.Rename of some Methods +| RocherKong | https://github.com/RocherKong | Creator | 20180209| 1.CodeStandardized 2.Support Netfx4.5 3.TestStandardized -你可以任意修改代码,但必须确保通过全部的单元测试。 -在此之前,请保证你已经安装了 Net4.6 和 Net Core 2.0 版本。 - -操作步骤: -1)使用 VS2017(推荐,可以到 https://visualstudio.microsoft.com/zh-hans/downloads/ 下载。),或者其它相关版本打开 IP2Region 项目。 -2)使用 VS 打开IP2Region 项目。 -3)保存 sln 文件到 c# 文件夹下(该文件应该自动被忽略)。 -4)右键点击“解决方案IP2Region”,添加 UnitTests 和 BenchmarkTest 项目。 -5)请右键点击整个解决方案,选择“重新生成解决方案”。 -6)菜单栏上“测试”=>“运行”=>“所有测试”,检测是否通过全部测试即可(你可以根据需要自行增加特定的单元测试)。 \ No newline at end of file