diff --git a/binding/csharp/IP2Region.Net.Test/SearcherTest.cs b/binding/csharp/IP2Region.Net.Test/SearcherTest.cs index e673301..15a3364 100644 --- a/binding/csharp/IP2Region.Net.Test/SearcherTest.cs +++ b/binding/csharp/IP2Region.Net.Test/SearcherTest.cs @@ -1,11 +1,117 @@ using IP2Region.Net.XDB; +using System.Buffers; +using System.Buffers.Binary; +using System.Net; +using System.Text; using Xunit; namespace IP2Region.Net.Test; public class SearcherTest { - private readonly string _xdbPath = Path.Combine(AppContext.BaseDirectory, "TestData", "ip2region_v4.xdb"); + private readonly string _xdbPath = Path.Combine(AppContext.BaseDirectory, "TestData", "ip2region_v6.xdb"); + + [Fact] + public void Test() + { + // 常量定义 + // 每个 vector 索引项的字节数 + var VectorIndexSize = 8; + + // vector 索引的列数 + var VectorIndexCols = 256; + + // vector 索引段整个的字节数 + var VectorIndexLength = 512; + + //var ipAddress = IPAddress.Parse("240e:3b7:3272:d8d0:db09:c067:8d59:539e"); + var ipAddress = IPAddress.Parse("2c0f:fda8:21::"); + // [36,14,3,183,50,114,216,208,219,9,192,103,141,89,83,158] + //var ipAddress = IPAddress.Parse("58.251.27.201"); + byte[] ip_bytes = ipAddress.GetAddressBytes(); + //Array.Reverse(bytes); + + //var ip = MemoryMarshal.Read(bytes); + + var il0 = ip_bytes[0] & 0xFF; + var il1 = ip_bytes[1] & 0xFF; + + var idx = il0 * VectorIndexCols * VectorIndexSize + il1 * VectorIndexSize; + + var data = Read(256 + idx, VectorIndexSize); + var sPtr = BinaryPrimitives.ReadUInt32LittleEndian(data.Span); + var ePtr = BinaryPrimitives.ReadUInt32LittleEndian(data.Span.Slice(4)); + + var indexSize = 38; + var l = 0; + var h = (ePtr - sPtr) / indexSize; + var dataLen = 0; + var dataPtr = 0l; + + var bytes = ip_bytes.Length; + var dBytes = ip_bytes.Length << 1; + var buff = new byte[indexSize]; + + while (l < h) + { + // 得到中间的索引项 + int m = (int)(l + h) >> 1; + + var p = (int)sPtr + m * indexSize; + + buff = Read(p, buff.Length).ToArray(); + + var s1 = BinaryPrimitives.ReadUInt32BigEndian(ip_bytes); + var s = BinaryPrimitives.ReadUInt32BigEndian(buff.AsSpan().Slice(0, ip_bytes.Length).ToArray()); + var e = BinaryPrimitives.ReadUInt32BigEndian(buff.AsSpan().Slice(ip_bytes.Length).ToArray()); + if (s1 < s) + { + h = m - 1; + } + else if (s1 > e) + { + l = m + 1; + } + else + { + dataLen = BinaryPrimitives.ReadUInt16LittleEndian(buff.AsSpan().Slice(dBytes, 2)); + dataPtr = BinaryPrimitives.ReadUInt32LittleEndian(buff.AsSpan().Slice(dBytes + 2)); + break; + } + } + + var regionBuff = Read((int)dataPtr, (int)dataLen); + var address = Encoding.UTF8.GetString(regionBuff.Span.ToArray()); + } + + private ReadOnlyMemory Read(int offset, int length) + { + int BufferSize = 4096; + + var stream = new FileStream(_xdbPath, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize, useAsync: true); + + byte[] buffer = ArrayPool.Shared.Rent(length); + int totalBytesRead = 0; + try + { + stream.Seek(offset, SeekOrigin.Begin); + + int bytesRead; + do + { + int bytesToRead = Math.Min(BufferSize, length - totalBytesRead); + bytesRead = stream.Read(buffer, totalBytesRead, bytesToRead); + totalBytesRead += bytesRead; + + } while (bytesRead > 0 && totalBytesRead < length); + } + finally + { + ArrayPool.Shared.Return(buffer); + } + + return new ReadOnlyMemory(buffer, 0, totalBytesRead); + } [Theory] [InlineData("114.114.114.114")]