Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Ip2region
提交
234c111f
I
Ip2region
项目概览
int
/
Ip2region
上一次同步 接近 1 年
通知
19
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
I
Ip2region
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
234c111f
编写于
9月 06, 2022
作者:
A
Alan
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat(csharp): 2.0 xdb csharp client implementation
上级
aec0b2fa
变更
21
隐藏空白更改
内联
并排
Showing
21 changed file
with
684070 addition
and
710 deletion
+684070
-710
binding/csharp/IP2Region.Net.BenchMark/IP2Region.Net.BenchMark.csproj
...rp/IP2Region.Net.BenchMark/IP2Region.Net.BenchMark.csproj
+19
-0
binding/csharp/IP2Region.Net.BenchMark/Program.cs
binding/csharp/IP2Region.Net.BenchMark/Program.cs
+21
-0
binding/csharp/IP2Region.Net.Test/IP2Region.Net.Test.csproj
binding/csharp/IP2Region.Net.Test/IP2Region.Net.Test.csproj
+33
-0
binding/csharp/IP2Region.Net.Test/SearcherTest.cs
binding/csharp/IP2Region.Net.Test/SearcherTest.cs
+75
-0
binding/csharp/IP2Region.Net.Test/TestData/ip.merge.txt
binding/csharp/IP2Region.Net.Test/TestData/ip.merge.txt
+683591
-0
binding/csharp/IP2Region.Net.Test/Usings.cs
binding/csharp/IP2Region.Net.Test/Usings.cs
+1
-0
binding/csharp/IP2Region.Net.Test/UtilTest.cs
binding/csharp/IP2Region.Net.Test/UtilTest.cs
+14
-0
binding/csharp/IP2Region.Net/IP2Region.Net.csproj
binding/csharp/IP2Region.Net/IP2Region.Net.csproj
+33
-0
binding/csharp/IP2Region.Net/XDB/CachePolicy.cs
binding/csharp/IP2Region.Net/XDB/CachePolicy.cs
+17
-0
binding/csharp/IP2Region.Net/XDB/ISearcher.cs
binding/csharp/IP2Region.Net/XDB/ISearcher.cs
+14
-0
binding/csharp/IP2Region.Net/XDB/Searcher.cs
binding/csharp/IP2Region.Net/XDB/Searcher.cs
+163
-0
binding/csharp/IP2Region.Net/XDB/Util.cs
binding/csharp/IP2Region.Net/XDB/Util.cs
+25
-0
binding/csharp/IP2Region.SearchTest/App.config
binding/csharp/IP2Region.SearchTest/App.config
+0
-6
binding/csharp/IP2Region.SearchTest/IP2Region.SearchTest.csproj
...g/csharp/IP2Region.SearchTest/IP2Region.SearchTest.csproj
+0
-59
binding/csharp/IP2Region.SearchTest/Program.cs
binding/csharp/IP2Region.SearchTest/Program.cs
+0
-263
binding/csharp/IP2Region.SearchTest/Properties/AssemblyInfo.cs
...ng/csharp/IP2Region.SearchTest/Properties/AssemblyInfo.cs
+0
-36
binding/csharp/IP2Region.sln
binding/csharp/IP2Region.sln
+0
-31
binding/csharp/IP2Region/IP2Region.csproj
binding/csharp/IP2Region/IP2Region.csproj
+0
-7
binding/csharp/IP2Region/xdb/Header.cs
binding/csharp/IP2Region/xdb/Header.cs
+0
-40
binding/csharp/IP2Region/xdb/Searcher.cs
binding/csharp/IP2Region/xdb/Searcher.cs
+0
-268
binding/csharp/README.md
binding/csharp/README.md
+64
-0
未找到文件。
binding/csharp/IP2Region.Net.BenchMark/IP2Region.Net.BenchMark.csproj
0 → 100644
浏览文件 @
234c111f
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.2" />
<PackageReference Include="BenchmarkDotNet.Annotations" Version="0.13.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\IP2Region.Net\IP2Region.Net.csproj" />
</ItemGroup>
</Project>
binding/csharp/IP2Region.Net.BenchMark/Program.cs
0 → 100644
浏览文件 @
234c111f
using
BenchmarkDotNet.Attributes
;
using
BenchmarkDotNet.Running
;
using
IP2Region.Net.XDB
;
BenchmarkRunner
.
Run
(
typeof
(
Program
).
Assembly
);
public
class
CachePolicyCompare
{
private
readonly
Searcher
_contentSearcher
=
new
Searcher
(
CachePolicy
.
Content
);
private
readonly
Searcher
_vectorSearcher
=
new
Searcher
(
CachePolicy
.
VectorIndex
);
private
readonly
string
_testIpAddress
=
"114.114.114.114"
;
[
Benchmark
]
[
BenchmarkCategory
(
nameof
(
CachePolicy
.
Content
))]
public
void
CachePolicy_Content
()
=>
_contentSearcher
.
Search
(
_testIpAddress
);
[
Benchmark
]
[
BenchmarkCategory
(
nameof
(
CachePolicy
.
VectorIndex
))]
public
void
CachePolicy_VectorIndex
()
=>
_vectorSearcher
.
Search
(
_testIpAddress
);
}
\ No newline at end of file
binding/csharp/IP2Region.Net.Test/IP2Region.Net.Test.csproj
0 → 100644
浏览文件 @
234c111f
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit.Analyzers" Version="3.3.0" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\IP2Region.Net\IP2Region.Net.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="TestData" />
</ItemGroup>
<ItemGroup>
<None Update="TestData\ip.merge.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
binding/csharp/IP2Region.Net.Test/SearcherTest.cs
0 → 100644
浏览文件 @
234c111f
using
IP2Region.Net.XDB
;
namespace
IP2Region.Net.Test
;
[
TestFixture
]
public
class
SearcherTest
{
public
static
IEnumerable
<
string
>
Ips
()
{
yield
return
"114.114.114.114"
;
yield
return
"119.29.29.29"
;
yield
return
"223.5.5.5"
;
yield
return
"180.76.76.76"
;
yield
return
"8.8.8.8"
;
}
[
TestCaseSource
(
nameof
(
Ips
))]
public
void
TestSearchCacheContent
(
string
ip
)
{
var
contentSearcher
=
new
Searcher
(
CachePolicy
.
Content
);
var
region
=
contentSearcher
.
Search
(
ip
);
Console
.
WriteLine
(
region
);
}
[
TestCaseSource
(
nameof
(
Ips
))]
public
void
TestSearchCacheVector
(
string
ip
)
{
var
vectorSearcher
=
new
Searcher
(
CachePolicy
.
VectorIndex
);
var
region
=
vectorSearcher
.
Search
(
ip
);
Console
.
WriteLine
(
region
);
}
[
TestCaseSource
(
nameof
(
Ips
))]
public
void
TestSearchCacheFile
(
string
ip
)
{
var
fileSearcher
=
new
Searcher
(
CachePolicy
.
File
);
var
region
=
fileSearcher
.
Search
(
ip
);
Console
.
WriteLine
(
region
);
}
[
TestCase
(
CachePolicy
.
Content
)]
[
TestCase
(
CachePolicy
.
VectorIndex
)]
[
TestCase
(
CachePolicy
.
File
)]
public
void
TestBenchSearch
(
CachePolicy
cachePolicy
)
{
Searcher
searcher
=
new
Searcher
(
cachePolicy
);
var
srcPath
=
Path
.
Combine
(
AppContext
.
BaseDirectory
,
"TestData"
,
"ip.merge.txt"
);
foreach
(
var
line
in
File
.
ReadLines
(
srcPath
))
{
var
ps
=
line
.
Trim
().
Split
(
"|"
,
3
);
if
(
ps
.
Length
!=
3
)
{
throw
new
ArgumentException
(
$"invalid ip segment line
{
line
}
"
,
nameof
(
line
));
}
var
sip
=
Util
.
IpAddressToUInt32
(
ps
[
0
]);
var
eip
=
Util
.
IpAddressToUInt32
(
ps
[
1
]);
var
mip
=
Util
.
GetMidIp
(
sip
,
eip
);
uint
[]
temp
=
{
sip
,
Util
.
GetMidIp
(
sip
,
mip
),
mip
,
Util
.
GetMidIp
(
mip
,
eip
),
eip
};
foreach
(
var
ip
in
temp
)
{
var
region
=
searcher
.
Search
(
ip
);
if
(
region
!=
ps
[
2
])
{
throw
new
Exception
(
$"failed search
{
ip
}
with (
{
region
}
!=
{
ps
[
2
]}
)"
);
}
}
}
}
}
\ No newline at end of file
binding/csharp/IP2Region.Net.Test/TestData/ip.merge.txt
0 → 100644
浏览文件 @
234c111f
因为 它太大了无法显示 source diff 。你可以改为
查看blob
。
binding/csharp/IP2Region.Net.Test/Usings.cs
0 → 100644
浏览文件 @
234c111f
global
using
NUnit.Framework
;
\ No newline at end of file
binding/csharp/IP2Region.Net.Test/UtilTest.cs
0 → 100644
浏览文件 @
234c111f
using
IP2Region.Net.XDB
;
namespace
IP2Region.Net.Test
;
[
TestFixture
]
public
class
UtilTest
{
[
TestCase
(
"114.114.114.114"
)]
public
void
TestIpAddressToUInt32
(
string
value
)
{
var
uintIp
=
XDB
.
Util
.
IpAddressToUInt32
(
value
);
Console
.
WriteLine
(
uintIp
);
}
}
\ No newline at end of file
binding/csharp/IP2Region.Net/IP2Region.Net.csproj
0 → 100644
浏览文件 @
234c111f
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<id>IP2Region.Net</id>
<version>1.0.2</version>
<title>IP2Region.Net</title>
<authors>Alan Lee</authors>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageProjectUrl>https://github.com/lionsoul2014/ip2region/tree/master/binding/csharp</PackageProjectUrl>
<RepositoryUrl>https://github.com/lionsoul2014/ip2region/tree/master/binding/csharp</RepositoryUrl>
<Description>ip2region 是一个离线IP地址定位库,极速响应,微秒级查询</Description>
<tags>IP2Region</tags>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TargetFrameworks>net6.0;netstandard2.1</TargetFrameworks>
<LangVersion>10.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<Folder Include="Data" />
</ItemGroup>
<ItemGroup>
<None Update="Data\ip2region.xdb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="..\README.md" Pack="true" PackagePath="\" />
</ItemGroup>
</Project>
binding/csharp/IP2Region.Net/XDB/CachePolicy.cs
0 → 100644
浏览文件 @
234c111f
namespace
IP2Region.Net.XDB
;
public
enum
CachePolicy
{
/// <summary>
/// no cache , not thread safe!
/// </summary>
File
,
/// <summary>
/// cache vector index , reduce the number of IO operations , not thread safe!
/// </summary>
VectorIndex
,
/// <summary>
/// default cache policy , cache whole xdb file , thread safe
/// </summary>
Content
}
\ No newline at end of file
binding/csharp/IP2Region.Net/XDB/ISearcher.cs
0 → 100644
浏览文件 @
234c111f
using
System.Net
;
namespace
IP2Region.Net.XDB
;
public
interface
ISearcher
{
string
?
Search
(
string
ipStr
);
string
?
Search
(
IPAddress
ipAddress
);
string
?
Search
(
uint
ipAddress
);
int
IoCount
{
get
;
}
}
\ No newline at end of file
binding/csharp/IP2Region.Net/XDB/Searcher.cs
0 → 100644
浏览文件 @
234c111f
// Copyright 2022 The Ip2Region Authors. All rights reserved.
// Use of this source code is governed by a Apache2.0-style
// license that can be found in the LICENSE file.
// @Author Alan Lee <lzh.shap@gmail.com>
// @Date 2022/09/06
using
System.Net
;
using
System.Text
;
namespace
IP2Region.Net.XDB
;
public
class
Searcher
:
ISearcher
{
const
int
HeaderInfoLength
=
256
;
const
int
VectorIndexRows
=
256
;
const
int
VectorIndexCols
=
256
;
const
int
VectorIndexSize
=
8
;
const
int
SegmentIndexSize
=
14
;
private
readonly
byte
[]?
_vectorIndex
;
private
readonly
byte
[]?
_contentBuff
;
private
readonly
FileStream
_contentStream
;
private
readonly
CachePolicy
_cachePolicy
;
public
int
IoCount
{
get
;
private
set
;
}
public
Searcher
(
CachePolicy
cachePolicy
=
CachePolicy
.
Content
,
string
?
dbPath
=
null
)
{
if
(
string
.
IsNullOrEmpty
(
dbPath
))
{
dbPath
=
Path
.
Combine
(
AppContext
.
BaseDirectory
,
"Data"
,
"ip2region.xdb"
);
}
_contentStream
=
File
.
OpenRead
(
dbPath
);
_cachePolicy
=
cachePolicy
;
switch
(
_cachePolicy
)
{
case
CachePolicy
.
Content
:
using
(
var
stream
=
new
MemoryStream
())
{
_contentStream
.
CopyTo
(
stream
);
_contentBuff
=
stream
.
ToArray
();
}
break
;
case
CachePolicy
.
VectorIndex
:
var
vectorLength
=
VectorIndexRows
*
VectorIndexCols
*
VectorIndexSize
;
_vectorIndex
=
new
byte
[
vectorLength
];
Read
(
HeaderInfoLength
,
_vectorIndex
);
break
;
}
}
~
Searcher
()
{
_contentStream
.
Close
();
_contentStream
.
Dispose
();
}
public
string
?
Search
(
string
ipStr
)
{
var
ip
=
Util
.
IpAddressToUInt32
(
ipStr
);
return
Search
(
ip
);
}
public
string
?
Search
(
IPAddress
ipAddress
)
{
var
ip
=
Util
.
IpAddressToUInt32
(
ipAddress
);
return
Search
(
ip
);
}
public
string
?
Search
(
uint
ip
)
{
var
il0
=
ip
>>
24
&
0xFF
;
var
il1
=
ip
>>
16
&
0xFF
;
var
idx
=
il0
*
VectorIndexCols
*
VectorIndexSize
+
il1
*
VectorIndexSize
;
uint
sPtr
=
0
,
ePtr
=
0
;
switch
(
_cachePolicy
)
{
case
CachePolicy
.
VectorIndex
:
sPtr
=
BitConverter
.
ToUInt32
(
_vectorIndex
.
AsSpan
()[(
int
)
idx
..]);
ePtr
=
BitConverter
.
ToUInt32
(
_vectorIndex
.
AsSpan
()[((
int
)
idx
+
4
)..]);
break
;
case
CachePolicy
.
Content
:
sPtr
=
BitConverter
.
ToUInt32
(
_contentBuff
.
AsSpan
()[(
HeaderInfoLength
+
(
int
)
idx
)..]);
ePtr
=
BitConverter
.
ToUInt32
(
_contentBuff
.
AsSpan
()[(
HeaderInfoLength
+
(
int
)
idx
+
4
)..]);
break
;
case
CachePolicy
.
File
:
var
buff
=
new
byte
[
VectorIndexSize
];
Read
((
int
)(
idx
+
HeaderInfoLength
),
buff
);
sPtr
=
BitConverter
.
ToUInt32
(
buff
);
ePtr
=
BitConverter
.
ToUInt32
(
buff
.
AsSpan
()[
4.
.]);
break
;
}
var
dataLen
=
0
;
uint
dataPtr
=
0
;
var
l
=
0
;
var
h
=
(
int
)((
ePtr
-
sPtr
)
/
SegmentIndexSize
);
var
buffer
=
new
byte
[
SegmentIndexSize
];
while
(
l
<=
h
)
{
var
mid
=
Util
.
GetMidIp
(
l
,
h
);
var
pos
=
sPtr
+
mid
*
SegmentIndexSize
;
Read
((
int
)
pos
,
buffer
);
var
sip
=
BitConverter
.
ToUInt32
(
buffer
);
if
(
ip
<
sip
)
{
h
=
mid
-
1
;
}
else
{
var
eip
=
BitConverter
.
ToUInt32
(
buffer
.
AsSpan
()[
4.
.]);
if
(
ip
>
eip
)
{
l
=
mid
+
1
;
}
else
{
dataLen
=
BitConverter
.
ToUInt16
(
buffer
.
AsSpan
()[
8.
.]);
dataPtr
=
BitConverter
.
ToUInt32
(
buffer
.
AsSpan
()[
10.
.]);
break
;
}
}
}
if
(
dataLen
==
0
)
{
return
default
;
}
var
regionBuff
=
new
byte
[
dataLen
];
Read
((
int
)
dataPtr
,
regionBuff
);
return
Encoding
.
UTF8
.
GetString
(
regionBuff
);
}
private
void
Read
(
int
offset
,
byte
[]
buff
)
{
switch
(
_cachePolicy
)
{
case
CachePolicy
.
Content
:
_contentBuff
.
AsSpan
()[
offset
..(
offset
+
buff
.
Length
)].
CopyTo
(
buff
);
break
;
default
:
_contentStream
.
Seek
(
offset
,
SeekOrigin
.
Begin
);
IoCount
++;
var
rLen
=
_contentStream
.
Read
(
buff
);
if
(
rLen
!=
buff
.
Length
)
{
throw
new
IOException
(
$"incomplete read: readed bytes should be
{
buff
.
Length
}
"
);
}
break
;
}
}
}
\ No newline at end of file
binding/csharp/IP2Region.Net/XDB/Util.cs
0 → 100644
浏览文件 @
234c111f
using
System.Net
;
namespace
IP2Region.Net.XDB
;
public
static
class
Util
{
public
static
uint
IpAddressToUInt32
(
string
ipAddress
)
{
var
address
=
IPAddress
.
Parse
(
ipAddress
);
return
IpAddressToUInt32
(
address
);
}
public
static
uint
IpAddressToUInt32
(
IPAddress
ipAddress
)
{
byte
[]
bytes
=
ipAddress
.
GetAddressBytes
();
Array
.
Reverse
(
bytes
);
return
BitConverter
.
ToUInt32
(
bytes
,
0
);
}
public
static
uint
GetMidIp
(
uint
x
,
uint
y
)
=>
(
x
&
y
)
+
((
x
^
y
)
>>
1
);
public
static
int
GetMidIp
(
int
x
,
int
y
)
=>
(
x
&
y
)
+
((
x
^
y
)
>>
1
);
}
\ No newline at end of file
binding/csharp/IP2Region.SearchTest/App.config
已删除
100644 → 0
浏览文件 @
aec0b2fa
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
configuration
>
<
startup
>
<
supportedRuntime
version
=
"v4.0"
sku
=
".NETFramework,Version=v4.7.2"
/>
</
startup
>
</
configuration
>
\ No newline at end of file
binding/csharp/IP2Region.SearchTest/IP2Region.SearchTest.csproj
已删除
100644 → 0
浏览文件 @
aec0b2fa
<?xml version="1.0" encoding="utf-8"?>
<Project
ToolsVersion=
"15.0"
xmlns=
"http://schemas.microsoft.com/developer/msbuild/2003"
>
<Import
Project=
"$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props"
Condition=
"Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')"
/>
<PropertyGroup>
<Configuration
Condition=
" '$(Configuration)' == '' "
>
Debug
</Configuration>
<Platform
Condition=
" '$(Platform)' == '' "
>
AnyCPU
</Platform>
<ProjectGuid>
{FF136AEA-D41F-4C14-842B-CE597BB97916}
</ProjectGuid>
<OutputType>
Exe
</OutputType>
<RootNamespace>
IP2Region.SearchTest
</RootNamespace>
<AssemblyName>
IP2Region.SearchTest
</AssemblyName>
<TargetFrameworkVersion>
v4.7.2
</TargetFrameworkVersion>
<FileAlignment>
512
</FileAlignment>
<AutoGenerateBindingRedirects>
true
</AutoGenerateBindingRedirects>
<Deterministic>
true
</Deterministic>
</PropertyGroup>
<PropertyGroup
Condition=
" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "
>
<PlatformTarget>
AnyCPU
</PlatformTarget>
<DebugSymbols>
true
</DebugSymbols>
<DebugType>
full
</DebugType>
<Optimize>
false
</Optimize>
<OutputPath>
bin\Debug\
</OutputPath>
<DefineConstants>
DEBUG;TRACE
</DefineConstants>
<ErrorReport>
prompt
</ErrorReport>
<WarningLevel>
4
</WarningLevel>
</PropertyGroup>
<PropertyGroup
Condition=
" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "
>
<PlatformTarget>
AnyCPU
</PlatformTarget>
<DebugType>
pdbonly
</DebugType>
<Optimize>
true
</Optimize>
<OutputPath>
bin\Release\
</OutputPath>
<DefineConstants>
TRACE
</DefineConstants>
<ErrorReport>
prompt
</ErrorReport>
<WarningLevel>
4
</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference
Include=
"System"
/>
<Reference
Include=
"System.Core"
/>
<Reference
Include=
"System.Xml.Linq"
/>
<Reference
Include=
"System.Data.DataSetExtensions"
/>
<Reference
Include=
"Microsoft.CSharp"
/>
<Reference
Include=
"System.Data"
/>
<Reference
Include=
"System.Net.Http"
/>
<Reference
Include=
"System.Xml"
/>
</ItemGroup>
<ItemGroup>
<Compile
Include=
"Program.cs"
/>
<Compile
Include=
"Properties\AssemblyInfo.cs"
/>
</ItemGroup>
<ItemGroup>
<None
Include=
"App.config"
/>
</ItemGroup>
<ItemGroup>
<ProjectReference
Include=
"..\IP2Region\IP2Region.csproj"
>
<Project>
{483575a5-ffb3-4131-a2dc-6d3ad3bb268f}
</Project>
<Name>
IP2Region
</Name>
</ProjectReference>
</ItemGroup>
<Import
Project=
"$(MSBuildToolsPath)\Microsoft.CSharp.targets"
/>
</Project>
\ No newline at end of file
binding/csharp/IP2Region.SearchTest/Program.cs
已删除
100644 → 0
浏览文件 @
aec0b2fa
using
IP2Region.xdb
;
using
System
;
using
System.Diagnostics
;
using
System.IO
;
namespace
IP2Region.SearchTest
{
internal
class
Program
{
public
static
void
PrintHelp
(
String
[]
args
)
{
Console
.
WriteLine
(
"ip2region xdb searcher"
);
Console
.
WriteLine
(
"IP2Region.SearchTest.exe [command] [command options]"
);
Console
.
WriteLine
(
"Command: "
);
Console
.
WriteLine
(
" search search input test"
);
Console
.
WriteLine
(
" bench search bench test"
);
}
public
static
Searcher
CreateSearcher
(
String
dbPath
,
String
cachePolicy
)
{
if
(
"file"
==
cachePolicy
)
{
return
Searcher
.
NewWithFileOnly
(
dbPath
);
}
else
if
(
"vectorIndex"
==
cachePolicy
)
{
byte
[]
vIndex
=
Searcher
.
LoadVectorIndexFromFile
(
dbPath
);
return
Searcher
.
NewWithVectorIndex
(
dbPath
,
vIndex
);
}
else
if
(
"content"
==
cachePolicy
)
{
byte
[]
cBuff
=
Searcher
.
LoadContentFromFile
(
dbPath
);
return
Searcher
.
NewWithBuffer
(
cBuff
);
}
else
{
throw
new
Exception
(
"invalid cache policy `"
+
cachePolicy
+
"`, options: file/vectorIndex/content"
);
}
}
public
static
void
SearchTest
(
string
[]
args
)
{
String
dbPath
=
""
,
cachePolicy
=
"vectorIndex"
;
foreach
(
string
r
in
args
)
{
if
(
r
.
Length
<
5
)
{
continue
;
}
if
(
r
.
IndexOf
(
"--"
)
!=
0
)
{
continue
;
}
int
sIdx
=
r
.
IndexOf
(
'='
);
if
(
sIdx
<
0
)
{
Console
.
WriteLine
(
"missing = for args pair `{0}`"
,
r
);
return
;
}
String
key
=
r
.
Substring
(
2
,
sIdx
-
2
);
String
val
=
r
.
Substring
(
sIdx
+
1
);
// Console.WriteLinef("key=%s, val=%s\n", key, val);
if
(
"db"
==
key
)
{
dbPath
=
val
;
}
else
if
(
"cache-policy"
==
key
)
{
cachePolicy
=
val
;
}
else
{
Console
.
WriteLine
(
"undefined option `{0}`"
,
r
);
return
;
}
}
if
(
dbPath
.
Length
<
1
)
{
Console
.
WriteLine
(
"IP2Region.SearchTest.exe search [command options]"
);
Console
.
WriteLine
(
"options:"
);
Console
.
WriteLine
(
" --db string ip2region binary xdb file path"
);
Console
.
WriteLine
(
" --cache-policy string cache policy: file/vectorIndex/content"
);
return
;
}
Searcher
searcher
=
CreateSearcher
(
dbPath
,
cachePolicy
);
Console
.
WriteLine
(
"ip2region xdb searcher test program, cachePolicy: {0}\ntype 'quit' to exit"
,
cachePolicy
);
while
(
true
)
{
Console
.
Write
(
"ip2region>> "
);
var
line
=
Console
.
ReadLine
().
Trim
();
if
(
line
.
Length
<
2
)
continue
;
if
(
line
==
"quit"
)
break
;
try
{
var
st
=
new
Stopwatch
();
st
.
Start
();
var
region
=
searcher
.
Search
(
line
);
st
.
Stop
();
var
cost
=
st
.
ElapsedMilliseconds
;
Console
.
WriteLine
(
"{{region: {0}, ioCount: {1}, took: {2} ms}}"
,
region
,
searcher
.
IOCount
,
cost
);
}
catch
(
Exception
e
)
{
Console
.
WriteLine
(
"{{err:{0}, ioCount: {1}}}"
,
e
,
searcher
.
IOCount
);
}
}
Console
.
WriteLine
(
"searcher test program exited, thanks for trying"
);
}
public
static
void
BenchTest
(
String
[]
args
)
{
String
dbPath
=
""
,
srcPath
=
""
,
cachePolicy
=
"vectorIndex"
;
foreach
(
String
r
in
args
)
{
if
(
r
.
Length
<
5
)
{
continue
;
}
if
(
r
.
IndexOf
(
"--"
)
!=
0
)
{
continue
;
}
int
sIdx
=
r
.
IndexOf
(
'='
);
if
(
sIdx
<
0
)
{
Console
.
WriteLine
(
"missing = for args pair `{0}`"
,
r
);
return
;
}
String
key
=
r
.
Substring
(
2
,
sIdx
-
2
);
String
val
=
r
.
Substring
(
sIdx
+
1
);
if
(
"db"
==
key
)
{
dbPath
=
val
;
}
else
if
(
"src"
==
key
)
{
srcPath
=
val
;
}
else
if
(
"cache-policy"
==
key
)
{
cachePolicy
=
val
;
}
else
{
Console
.
WriteLine
(
"undefined option `{0}`"
,
r
);
return
;
}
}
if
(
dbPath
.
Length
<
1
||
srcPath
.
Length
<
1
)
{
Console
.
WriteLine
(
"IP2Region.SearchTest.exe bench [command options]"
);
Console
.
WriteLine
(
"options:"
);
Console
.
WriteLine
(
" --db string ip2region binary xdb file path"
);
Console
.
WriteLine
(
" --src string source ip text file path"
);
Console
.
WriteLine
(
" --cache-policy string cache policy: file/vectorIndex/content"
);
return
;
}
Searcher
searcher
=
CreateSearcher
(
dbPath
,
cachePolicy
);
long
count
=
0
;
var
sw
=
new
Stopwatch
();
var
lines
=
File
.
ReadAllLines
(
srcPath
);
foreach
(
var
line
in
lines
)
{
String
l
=
line
.
Trim
();
String
[]
ps
=
l
.
Split
(
new
[]
{
'|'
},
3
);
if
(
ps
.
Length
!=
3
)
{
Console
.
WriteLine
(
"invalid ip segment `{0}`"
,
l
);
return
;
}
long
sip
;
try
{
sip
=
Searcher
.
checkIP
(
ps
[
0
]);
}
catch
(
Exception
e
)
{
Console
.
WriteLine
(
"check start ip `{0}`: {1}"
,
ps
[
0
],
e
);
return
;
}
long
eip
;
try
{
eip
=
Searcher
.
checkIP
(
ps
[
1
]);
}
catch
(
Exception
e
)
{
Console
.
WriteLine
(
"check end ip `{0}`: {1}"
,
ps
[
1
],
e
);
return
;
}
if
(
sip
>
eip
)
{
Console
.
WriteLine
(
"start ip({0}) should not be greater than end ip({1})"
,
ps
[
0
],
ps
[
1
]);
return
;
}
long
mip
=
(
sip
+
eip
)
>>
1
;
foreach
(
var
ip
in
new
long
[]
{
sip
,
(
sip
+
mip
)
>>
1
,
mip
,
(
mip
+
eip
)
>>
1
,
eip
})
{
sw
.
Start
();
String
region
=
searcher
.
Search
(
ip
);
sw
.
Stop
();
// check the region info
if
(
ps
[
2
]
!=
(
region
))
{
Console
.
WriteLine
(
"failed search({0}) with ({1} != {2})\n"
,
Searcher
.
Long2ip
(
ip
),
region
,
ps
[
2
]);
return
;
}
count
++;
}
}
Console
.
WriteLine
(
"Bench finished, {{cachePolicy: {0}, total: {1}, took: {2}, cost: {3} ms/op}}"
,
cachePolicy
,
count
,
sw
.
Elapsed
,
count
==
0
?
0
:
sw
.
ElapsedMilliseconds
/
count
);
}
static
void
Main
(
string
[]
args
)
{
if
(
args
.
Length
<
1
)
{
PrintHelp
(
args
);
return
;
}
switch
(
args
[
0
])
{
case
"search"
:
try
{
SearchTest
(
args
);
}
catch
(
Exception
e
)
{
Console
.
WriteLine
(
"failed running search test: {0}"
,
e
);
}
break
;
case
"bench"
:
try
{
BenchTest
(
args
);
}
catch
(
Exception
e
)
{
Console
.
WriteLine
(
"failed running bench test: {0}"
,
e
);
}
break
;
default
:
PrintHelp
(
args
);
break
;
}
}
}
}
binding/csharp/IP2Region.SearchTest/Properties/AssemblyInfo.cs
已删除
100644 → 0
浏览文件 @
aec0b2fa
using
System.Reflection
;
using
System.Runtime.CompilerServices
;
using
System.Runtime.InteropServices
;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[
assembly
:
AssemblyTitle
(
"IP2Region.SearchTest"
)]
[
assembly
:
AssemblyDescription
(
""
)]
[
assembly
:
AssemblyConfiguration
(
""
)]
[
assembly
:
AssemblyCompany
(
""
)]
[
assembly
:
AssemblyProduct
(
"IP2Region.SearchTest"
)]
[
assembly
:
AssemblyCopyright
(
"Copyright © 2022"
)]
[
assembly
:
AssemblyTrademark
(
""
)]
[
assembly
:
AssemblyCulture
(
""
)]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[
assembly
:
ComVisible
(
false
)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[
assembly
:
Guid
(
"ff136aea-d41f-4c14-842b-ce597bb97916"
)]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[
assembly
:
AssemblyVersion
(
"1.0.0.0"
)]
[
assembly
:
AssemblyFileVersion
(
"1.0.0.0"
)]
binding/csharp/IP2Region.sln
已删除
100644 → 0
浏览文件 @
aec0b2fa
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32228.430
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IP2Region", "IP2Region\IP2Region.csproj", "{483575A5-FFB3-4131-A2DC-6D3AD3BB268F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IP2Region.SearchTest", "IP2Region.SearchTest\IP2Region.SearchTest.csproj", "{FF136AEA-D41F-4C14-842B-CE597BB97916}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{483575A5-FFB3-4131-A2DC-6D3AD3BB268F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{483575A5-FFB3-4131-A2DC-6D3AD3BB268F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{483575A5-FFB3-4131-A2DC-6D3AD3BB268F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{483575A5-FFB3-4131-A2DC-6D3AD3BB268F}.Release|Any CPU.Build.0 = Release|Any CPU
{FF136AEA-D41F-4C14-842B-CE597BB97916}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FF136AEA-D41F-4C14-842B-CE597BB97916}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF136AEA-D41F-4C14-842B-CE597BB97916}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF136AEA-D41F-4C14-842B-CE597BB97916}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6AEA440B-0D90-4F6E-BA9A-D42B27A78D7B}
EndGlobalSection
EndGlobal
binding/csharp/IP2Region/IP2Region.csproj
已删除
100644 → 0
浏览文件 @
aec0b2fa
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
</PropertyGroup>
</Project>
binding/csharp/IP2Region/xdb/Header.cs
已删除
100644 → 0
浏览文件 @
aec0b2fa
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Threading.Tasks
;
namespace
IP2Region.xdb
{
public
class
Header
{
public
int
Version
{
get
;
}
public
int
IndexPolicy
{
get
;
}
public
int
CreatedAt
{
get
;
}
public
int
StartIndexPtr
{
get
;
}
public
int
EndIndexPtr
{
get
;
}
public
byte
[]
Buffer
{
get
;
}
public
Header
(
byte
[]
buff
)
{
if
(
buff
==
null
)
throw
new
ArgumentNullException
(
nameof
(
buff
));
if
(
buff
.
Length
<
16
)
throw
new
ArgumentOutOfRangeException
(
nameof
(
buff
));
Version
=
Searcher
.
GetInt2
(
buff
,
0
);
IndexPolicy
=
Searcher
.
GetInt2
(
buff
,
2
);
CreatedAt
=
Searcher
.
GetInt
(
buff
,
4
);
StartIndexPtr
=
Searcher
.
GetInt
(
buff
,
8
);
EndIndexPtr
=
Searcher
.
GetInt
(
buff
,
12
);
Buffer
=
buff
;
}
public
override
string
ToString
()
{
return
"{"
+
"Version: "
+
Version
+
','
+
"IndexPolicy: "
+
IndexPolicy
+
','
+
"CreatedAt: "
+
CreatedAt
+
','
+
"StartIndexPtr: "
+
StartIndexPtr
+
','
+
"EndIndexPtr: "
+
EndIndexPtr
+
'}'
;
}
}
}
binding/csharp/IP2Region/xdb/Searcher.cs
已删除
100644 → 0
浏览文件 @
aec0b2fa
using
System
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.Linq
;
using
System.Text
;
using
System.Threading.Tasks
;
namespace
IP2Region.xdb
{
public
class
Searcher
{
// constant defined copied from the xdb maker
public
static
int
HeaderInfoLength
=
256
;
public
static
int
VectorIndexRows
=
256
;
public
static
int
VectorIndexCols
=
256
;
public
static
int
VectorIndexSize
=
8
;
public
static
int
SegmentIndexSize
=
14
;
// random access file handle for file based search
private
readonly
Stream
handle
;
private
int
ioCount
=
0
;
public
int
IOCount
=>
this
.
ioCount
;
// vector index.
// use the byte[] instead of VectorIndex entry array to keep
// the minimal memory allocation.
private
readonly
byte
[]
vectorIndex
;
// xdb content buffer, used for in-memory search
private
readonly
byte
[]
contentBuff
;
// --- static method to create searchers
public
static
Searcher
NewWithFileOnly
(
String
dbPath
)
{
return
new
Searcher
(
dbPath
,
null
,
null
);
}
public
static
Searcher
NewWithVectorIndex
(
String
dbPath
,
byte
[]
vectorIndex
)
{
return
new
Searcher
(
dbPath
,
vectorIndex
,
null
);
}
public
static
Searcher
NewWithBuffer
(
byte
[]
cBuff
)
{
return
new
Searcher
(
null
,
null
,
cBuff
);
}
// --- End of creator
public
Searcher
(
string
dbFile
,
byte
[]
vectorIndex
,
byte
[]
cBuff
)
{
if
(
cBuff
!=
null
)
{
this
.
handle
=
null
;
this
.
vectorIndex
=
null
;
this
.
contentBuff
=
cBuff
;
}
else
{
this
.
handle
=
File
.
OpenRead
(
dbFile
);
this
.
vectorIndex
=
vectorIndex
;
this
.
contentBuff
=
null
;
}
}
public
void
Close
()
{
if
(
this
.
handle
!=
null
)
this
.
handle
.
Close
();
}
public
string
Search
(
string
ipStr
)
{
var
ip
=
checkIP
(
ipStr
);
return
Search
(
ip
);
}
public
string
Search
(
long
ip
)
{
// reset the global counter
this
.
ioCount
=
0
;
// locate the segment index block based on the vector index
int
sPtr
=
0
,
ePtr
=
0
;
int
il0
=
(
int
)((
ip
>>
24
)
&
0xFF
);
int
il1
=
(
int
)((
ip
>>
16
)
&
0xFF
);
int
idx
=
il0
*
VectorIndexCols
*
VectorIndexSize
+
il1
*
VectorIndexSize
;
if
(
vectorIndex
!=
null
)
{
sPtr
=
GetInt
(
vectorIndex
,
idx
);
ePtr
=
GetInt
(
vectorIndex
,
idx
+
4
);
}
else
if
(
contentBuff
!=
null
)
{
sPtr
=
GetInt
(
contentBuff
,
HeaderInfoLength
+
idx
);
ePtr
=
GetInt
(
contentBuff
,
HeaderInfoLength
+
idx
+
4
);
}
else
{
byte
[]
vectorBuff
=
new
byte
[
VectorIndexSize
];
Read
(
HeaderInfoLength
+
idx
,
vectorBuff
);
sPtr
=
GetInt
(
vectorBuff
,
0
);
ePtr
=
GetInt
(
vectorBuff
,
4
);
}
// binary search the segment index block to get the region info
byte
[]
buff
=
new
byte
[
SegmentIndexSize
];
int
dataLen
=
-
1
,
dataPtr
=
-
1
;
int
l
=
0
,
h
=
(
ePtr
-
sPtr
)
/
SegmentIndexSize
;
while
(
l
<=
h
)
{
int
m
=
(
l
+
h
)
>>
1
;
int
p
=
sPtr
+
m
*
SegmentIndexSize
;
// read the segment index
Read
(
p
,
buff
);
long
sip
=
GetIntLong
(
buff
,
0
);
if
(
ip
<
sip
)
{
h
=
m
-
1
;
}
else
{
long
eip
=
GetIntLong
(
buff
,
4
);
if
(
ip
>
eip
)
{
l
=
m
+
1
;
}
else
{
dataLen
=
GetInt2
(
buff
,
8
);
dataPtr
=
GetInt
(
buff
,
10
);
break
;
}
}
}
// empty match interception
// System.out.printf("dataLen: %d, dataPtr: %d\n", dataLen, dataPtr);
if
(
dataPtr
<
0
)
return
null
;
// load and return the region data
byte
[]
regionBuff
=
new
byte
[
dataLen
];
Read
(
dataPtr
,
regionBuff
);
//return new String(regionBuff, "utf-8");
return
Encoding
.
UTF8
.
GetString
(
regionBuff
);
}
protected
virtual
void
Read
(
int
offset
,
byte
[]
buffer
)
{
// check the in-memory buffer first
if
(
contentBuff
!=
null
)
{
// @TODO: reduce data copying, directly decode the data ?
//System.arraycopy(contentBuff, offset, buffer, 0, buffer.length);
Array
.
Copy
(
contentBuff
,
offset
,
buffer
,
0
,
buffer
.
Length
);
return
;
}
// read from the file handle
if
(
handle
==
null
)
throw
new
ArgumentNullException
(
nameof
(
handle
));
handle
.
Seek
(
offset
,
SeekOrigin
.
Begin
);
this
.
ioCount
++;
var
rLen
=
handle
.
Read
(
buffer
,
0
,
buffer
.
Length
);
if
(
rLen
!=
buffer
.
Length
)
throw
new
IOException
(
"incomplete read: read bytes should be "
+
buffer
.
Length
);
}
// --- static cache util function
public
static
Header
LoadHeader
(
Stream
stream
)
{
stream
.
Seek
(
0
,
SeekOrigin
.
Begin
);
var
buffer
=
new
byte
[
HeaderInfoLength
];
stream
.
Read
(
buffer
,
0
,
HeaderInfoLength
);
return
new
Header
(
buffer
);
}
public
static
Header
LoadHeaderFromFile
(
string
dbPath
)
{
using
(
var
fs
=
File
.
OpenRead
(
dbPath
))
return
LoadHeader
(
fs
);
}
public
static
byte
[]
LoadVectorIndex
(
Stream
stream
)
{
stream
.
Seek
(
HeaderInfoLength
,
SeekOrigin
.
Begin
);
int
len
=
VectorIndexRows
*
VectorIndexCols
*
SegmentIndexSize
;
var
buff
=
new
byte
[
len
];
var
rLen
=
stream
.
Read
(
buff
,
0
,
buff
.
Length
);
if
(
rLen
!=
len
)
throw
new
IOException
(
"incomplete read: read bytes should be "
+
len
);
return
buff
;
}
public
static
byte
[]
LoadVectorIndexFromFile
(
string
dbPath
)
{
using
(
var
fs
=
File
.
OpenRead
(
dbPath
))
return
LoadVectorIndex
(
fs
);
}
public
static
byte
[]
LoadContent
(
Stream
stream
)
{
stream
.
Seek
(
0
,
SeekOrigin
.
Begin
);
using
(
var
ms
=
new
MemoryStream
())
{
stream
.
CopyTo
(
ms
);
return
ms
.
ToArray
();
}
}
public
static
byte
[]
LoadContentFromFile
(
string
dbPath
)
{
using
(
var
fs
=
File
.
OpenRead
(
dbPath
))
return
LoadContent
(
fs
);
}
public
static
int
GetInt2
(
byte
[]
b
,
int
offset
)
{
return
(
(
b
[
offset
++]
&
0x000000FF
)
|
(
b
[
offset
]
&
0x0000FF00
)
);
}
public
static
int
GetInt
(
byte
[]
b
,
int
offset
)
{
return
(
((
b
[
offset
++])
&
0x000000FF
)
|
((
b
[
offset
++]
<<
8
)
&
0x0000FF00
)
|
((
b
[
offset
++]
<<
16
)
&
0x00FF0000
)
|
(
int
)((
b
[
offset
]
<<
24
)
&
0xFF000000
)
);
}
public
static
long
GetIntLong
(
byte
[]
b
,
int
offset
)
{
return
(
((
b
[
offset
++]
&
0x000000FFL
))
|
((
b
[
offset
++]
<<
8
)
&
0x0000FF00L
)
|
((
b
[
offset
++]
<<
16
)
&
0x00FF0000L
)
|
((
b
[
offset
]
<<
24
)
&
0xFF000000L
)
);
}
/* long int to ip string */
public
static
string
Long2ip
(
long
ip
)
{
return
string
.
Join
(
"."
,
(
ip
>>
24
)
&
0xFF
,
(
ip
>>
16
)
&
0xFF
,
(
ip
>>
8
)
&
0xFF
,
(
ip
)
&
0xFF
);
}
public
static
byte
[]
shiftIndex
=
{
24
,
16
,
8
,
0
};
/* check the specified ip address */
public
static
long
checkIP
(
String
ip
)
{
String
[]
ps
=
ip
.
Split
(
'.'
);
if
(
ps
.
Length
!=
4
)
throw
new
Exception
(
"invalid ip address `"
+
ip
+
"`"
);
long
ipDst
=
0
;
for
(
int
i
=
0
;
i
<
ps
.
Length
;
i
++)
{
int
val
=
Convert
.
ToInt32
(
ps
[
i
]);
if
(
val
>
255
)
{
throw
new
Exception
(
"ip part `"
+
ps
[
i
]
+
"` should be less then 256"
);
}
ipDst
|=
((
long
)
val
<<
shiftIndex
[
i
]);
}
return
ipDst
&
0xFFFFFFFFL
;
}
}
}
binding/csharp/README.md
0 → 100644
浏览文件 @
234c111f
# IP2Region.Net
IP2Region c# xdb client
## Installation
Install the package with
[
NuGet
](
https://www.nuget.org/packages/IP2Region.Net
)
```
bash
Install-Package IP2Region.Net
```
## Usage
```
csharp
using
IP2Region.Net.XDB
;
//use default db and cache whole xdb file
Searcher
searcher
=
new
Searcher
();
searcher
.
Search
(
"ipaddress value"
);
/*
* custom cache policy and xdb file path
* CachePolicy.Content default cache policy , cache whole xdb file , thread safe
* CachePolicy.VectorIndex cache vector index , reduce the number of IO operations , not thread safe!
* CachePolicy.File no cache , not thread safe!
*/
Searcher
searcher
=
new
Searcher
(
CachePolicy
.
File
,
"your xdb file path"
);
```
## ASP.NET Core Usage
```
csharp
services
.
AddSingleton
<
ISearcher
,
Searcher
>();
```
## Performance
```
ini
BenchmarkDotNet
=
v0.13.2, OS=Windows 11 (10.0.22000.856/21H2)
AMD
Ryzen
5
3550H
with
Radeon
Vega
Mobile
Gfx,
1
CPU,
8
logical
and
4
physical
cores
.NET
SDK
=
6.0.400
[Host]
:
.NET
6.0.8
(6.0.822.36306),
X64
RyuJIT
AVX2
DefaultJob
:
.NET
6.0.8
(6.0.822.36306),
X64
RyuJIT
AVX2
```
| Method | Mean | Error | StdDev |
|------------------------ |------------:|----------:|----------:|
| CachePolicy_Content | 224.6 ns | 4.44 ns | 7.41 ns |
| CachePolicy_VectorIndex | 11,648.4 ns | 231.98 ns | 457.91 ns |
## Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Please make sure to update tests as appropriate.
## License
[
Apache License 2.0
](
https://github.com/lionsoul2014/ip2region/blob/master/LICENSE.md
)
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录