tanghai 7 年 前
コミット
20a4cb6fd2
33 ファイル変更901 行追加1360 行削除
  1. 16 1
      Client-Server.sln
  2. 2 2
      Server/Hotfix/Module/Benchmark/BenchmarkComponentSystem.cs
  3. 2 2
      Server/Hotfix/Module/Message/NetOuterComponentSystem.cs
  4. 6 1
      Server/Model/Server.Model.csproj
  5. 15 0
      Server/Server.sln
  6. 4 1
      Server/ThirdParty/Google.Protobuf/Google.Protobuf.csproj
  7. 30 0
      Server/ThirdParty/Libs/KcpLib.csproj
  8. BIN
      Server/ThirdParty/Libs/libkcp.so
  9. 8 0
      Unity/Assets/Plugins/Android.meta
  10. 9 0
      Unity/Assets/Plugins/Android/libs.meta
  11. 9 0
      Unity/Assets/Plugins/Android/libs/armeabi-v7a.meta
  12. BIN
      Unity/Assets/Plugins/Android/libs/armeabi-v7a/libkcp.so
  13. 9 9
      Unity/Assets/Plugins/Android/libs/armeabi-v7a/libkcp.so.meta
  14. 9 0
      Unity/Assets/Plugins/Android/libs/x86.meta
  15. BIN
      Unity/Assets/Plugins/Android/libs/x86/libkcp.so
  16. 34 0
      Unity/Assets/Plugins/Android/libs/x86/libkcp.so.meta
  17. BIN
      Unity/Assets/Plugins/Newtonsoft.Json.dll
  18. 8 0
      Unity/Assets/Plugins/x86.meta
  19. BIN
      Unity/Assets/Plugins/x86/kcp.dll
  20. 122 0
      Unity/Assets/Plugins/x86/kcp.dll.meta
  21. 8 0
      Unity/Assets/Plugins/x86_64.meta
  22. BIN
      Unity/Assets/Plugins/x86_64/kcp.dll
  23. 122 0
      Unity/Assets/Plugins/x86_64/kcp.dll.meta
  24. 24 5
      Unity/Assets/Scripts/Base/Helper/ByteHelper.cs
  25. 0 2
      Unity/Assets/Scripts/Base/MultiMap.cs
  26. 5 2
      Unity/Assets/Scripts/Module/Message/ErrorCode.cs
  27. 1 1
      Unity/Assets/Scripts/Module/Message/NetOuterComponent.cs
  28. 239 101
      Unity/Assets/Scripts/Module/Message/Network/KCP/KChannel.cs
  29. 120 98
      Unity/Assets/Scripts/Module/Message/Network/KCP/KService.cs
  30. 78 1102
      Unity/Assets/Scripts/Module/Message/Network/KCP/Kcp.cs
  31. 8 12
      Unity/Assets/Scripts/Module/Message/Network/TCP/PacketParser.cs
  32. 0 5
      Unity/Assets/Scripts/Module/Message/Network/TCP/TChannel.cs
  33. 13 16
      Unity/Assets/Scripts/Module/Message/Session.cs

+ 16 - 1
Client-Server.sln

@@ -33,7 +33,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MongoDB.Driver", "Server\Th
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MongoDB.Driver.Core", "Server\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Driver.Core\MongoDB.Driver.Core.csproj", "{831276B2-B7EB-4FD0-93E5-4D2109C78950}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Google.Protobuf", "Server\ThirdParty\Google.Protobuf\Google.Protobuf.csproj", "{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Google.Protobuf", "Server\ThirdParty\Google.Protobuf\Google.Protobuf.csproj", "{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KcpLib", "Server\ThirdParty\Libs\KcpLib.csproj", "{B055A8CF-EF01-4100-A73F-9A26CBBBC57F}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -189,6 +191,18 @@ Global
 		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Release|x64.Build.0 = Release|Any CPU
 		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Release|x86.ActiveCfg = Release|Any CPU
 		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Release|x86.Build.0 = Release|Any CPU
+		{B055A8CF-EF01-4100-A73F-9A26CBBBC57F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B055A8CF-EF01-4100-A73F-9A26CBBBC57F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B055A8CF-EF01-4100-A73F-9A26CBBBC57F}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{B055A8CF-EF01-4100-A73F-9A26CBBBC57F}.Debug|x64.Build.0 = Debug|Any CPU
+		{B055A8CF-EF01-4100-A73F-9A26CBBBC57F}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{B055A8CF-EF01-4100-A73F-9A26CBBBC57F}.Debug|x86.Build.0 = Debug|Any CPU
+		{B055A8CF-EF01-4100-A73F-9A26CBBBC57F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B055A8CF-EF01-4100-A73F-9A26CBBBC57F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B055A8CF-EF01-4100-A73F-9A26CBBBC57F}.Release|x64.ActiveCfg = Release|Any CPU
+		{B055A8CF-EF01-4100-A73F-9A26CBBBC57F}.Release|x64.Build.0 = Release|Any CPU
+		{B055A8CF-EF01-4100-A73F-9A26CBBBC57F}.Release|x86.ActiveCfg = Release|Any CPU
+		{B055A8CF-EF01-4100-A73F-9A26CBBBC57F}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -208,6 +222,7 @@ Global
 		{6D19C1F8-085C-422E-8DAF-2E49024DB08C} = {4940CE10-6652-4AC6-9D30-CF200A217643}
 		{831276B2-B7EB-4FD0-93E5-4D2109C78950} = {4940CE10-6652-4AC6-9D30-CF200A217643}
 		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B} = {78640FA0-9F11-412D-A639-61F03D02407A}
+		{B055A8CF-EF01-4100-A73F-9A26CBBBC57F} = {78640FA0-9F11-412D-A639-61F03D02407A}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {EABC01E3-3EB5-47EF-B46E-AAD8BB3585F1}

+ 2 - 2
Server/Hotfix/Module/Benchmark/BenchmarkComponentSystem.cs

@@ -21,7 +21,7 @@ namespace ETHotfix
 			try
 			{
 				NetOuterComponent networkComponent = Game.Scene.GetComponent<NetOuterComponent>();
-				for (int i = 0; i < 100; i++)
+				for (int i = 0; i < 1000; i++)
 				{
 					self.TestAsync(networkComponent, ipEndPoint, i);
 				}
@@ -71,7 +71,7 @@ namespace ETHotfix
 				long time2 = TimeHelper.ClientNow();
 				long time = time2 - self.time1;
 				self.time1 = time2;
-				Log.Info($"Benchmark k: {self.k} 每10W次耗时: {time} ms");
+				Log.Info($"Benchmark k: {self.k} 每10W次耗时: {time} ms {session.Network.Count}");
 			}
 			catch (Exception e)
 			{

+ 2 - 2
Server/Hotfix/Module/Message/NetOuterComponentSystem.cs

@@ -8,7 +8,7 @@ namespace ETHotfix
 	{
 		public override void Awake(NetOuterComponent self)
 		{
-			self.Awake(NetworkProtocol.TCP);
+			self.Awake(NetworkProtocol.KCP);
 			self.MessagePacker = new ProtobufPacker();
 			self.MessageDispatcher = new OuterMessageDispatcher();
 		}
@@ -19,7 +19,7 @@ namespace ETHotfix
 	{
 		public override void Awake(NetOuterComponent self, IPEndPoint ipEndPoint)
 		{
-			self.Awake(NetworkProtocol.TCP, ipEndPoint);
+			self.Awake(NetworkProtocol.KCP, ipEndPoint);
 			self.MessagePacker = new ProtobufPacker();
 			self.MessageDispatcher = new OuterMessageDispatcher();
 		}

+ 6 - 1
Server/Model/Server.Model.csproj

@@ -15,6 +15,11 @@
     <DefineConstants>TRACE;RELEASE;NETCOREAPP2_0;SERVER</DefineConstants>
     <OutputPath>..\..\Bin\</OutputPath>
   </PropertyGroup>
+  <ItemGroup>
+    <Compile Remove="Libs\**" />
+    <EmbeddedResource Remove="Libs\**" />
+    <None Remove="Libs\**" />
+  </ItemGroup>
   <ItemGroup>
     <Compile Include="..\..\Unity\Assets\Scripts\Base\DoubleMap.cs" Link="Base\DoubleMap.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Base\Event\Env.cs" Link="Base\Event\Env.cs" />
@@ -88,7 +93,6 @@
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\Network\AService.cs" Link="Module\Message\Network\AService.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\Network\Circularbuffer.cs" Link="Module\Message\Network\Circularbuffer.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\Network\KCP\KChannel.cs" Link="Module\Message\Network\KCP\KChannel.cs" />
-    <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\Network\KCP\Kcp.cs" Link="Module\Message\Network\KCP\Kcp.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\Network\KCP\KService.cs" Link="Module\Message\Network\KCP\KService.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\Network\NetworkHelper.cs" Link="Module\Message\Network\NetworkHelper.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\Network\TCP\PacketParser.cs" Link="Module\Message\Network\TCP\PacketParser.cs" />
@@ -116,6 +120,7 @@
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\ThirdParty\Google.Protobuf\Google.Protobuf.csproj" />
+    <ProjectReference Include="..\ThirdParty\Libs\KcpLib.csproj" />
     <ProjectReference Include="..\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Bson\MongoDB.Bson.csproj" />
     <ProjectReference Include="..\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Driver.Core\MongoDB.Driver.Core.csproj" />
     <ProjectReference Include="..\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Driver\MongoDB.Driver.csproj" />

+ 15 - 0
Server/Server.sln

@@ -21,6 +21,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MongoDB.Driver.Core", "Thir
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Google.Protobuf", "ThirdParty\Google.Protobuf\Google.Protobuf.csproj", "{02B4D7EC-AC40-4675-963E-53CAB9A86BDE}"
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KcpLib", "ThirdParty\Libs\KcpLib.csproj", "{9C71523E-4F8A-4F13-9884-DF580BAC8194}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -115,6 +117,18 @@ Global
 		{02B4D7EC-AC40-4675-963E-53CAB9A86BDE}.Release|x64.Build.0 = Release|Any CPU
 		{02B4D7EC-AC40-4675-963E-53CAB9A86BDE}.Release|x86.ActiveCfg = Release|Any CPU
 		{02B4D7EC-AC40-4675-963E-53CAB9A86BDE}.Release|x86.Build.0 = Release|Any CPU
+		{9C71523E-4F8A-4F13-9884-DF580BAC8194}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9C71523E-4F8A-4F13-9884-DF580BAC8194}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9C71523E-4F8A-4F13-9884-DF580BAC8194}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{9C71523E-4F8A-4F13-9884-DF580BAC8194}.Debug|x64.Build.0 = Debug|Any CPU
+		{9C71523E-4F8A-4F13-9884-DF580BAC8194}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{9C71523E-4F8A-4F13-9884-DF580BAC8194}.Debug|x86.Build.0 = Debug|Any CPU
+		{9C71523E-4F8A-4F13-9884-DF580BAC8194}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9C71523E-4F8A-4F13-9884-DF580BAC8194}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9C71523E-4F8A-4F13-9884-DF580BAC8194}.Release|x64.ActiveCfg = Release|Any CPU
+		{9C71523E-4F8A-4F13-9884-DF580BAC8194}.Release|x64.Build.0 = Release|Any CPU
+		{9C71523E-4F8A-4F13-9884-DF580BAC8194}.Release|x86.ActiveCfg = Release|Any CPU
+		{9C71523E-4F8A-4F13-9884-DF580BAC8194}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -125,6 +139,7 @@ Global
 		{3FD1D683-59E8-47C4-9436-B3D856EFB094} = {6946DBCF-B81C-4B2A-A7C5-94A337D915C2}
 		{46A590DE-EBA3-4928-AB78-5C514D08C9E7} = {6946DBCF-B81C-4B2A-A7C5-94A337D915C2}
 		{02B4D7EC-AC40-4675-963E-53CAB9A86BDE} = {5D11E730-0CAA-4A47-BA1A-379004F0F6D9}
+		{9C71523E-4F8A-4F13-9884-DF580BAC8194} = {5D11E730-0CAA-4A47-BA1A-379004F0F6D9}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {EE120158-643A-409C-B8F2-5E654E4D6D70}

+ 4 - 1
Server/ThirdParty/Google.Protobuf/Google.Protobuf.csproj

@@ -6,11 +6,14 @@
     <StartupObject />
   </PropertyGroup>
   <PropertyGroup>
-  	<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
+    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
     <OutputPath>..\..\..\Bin\</OutputPath>
   </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
+    <OutputPath>..\..\..\Bin\</OutputPath>
+  </PropertyGroup>
   <ItemGroup>
     <Compile Include="..\..\..\Unity\Assets\ThirdParty\Google.Protobuf\ByteArray.cs" Link="ByteArray.cs" />
     <Compile Include="..\..\..\Unity\Assets\ThirdParty\Google.Protobuf\ByteString.cs" Link="ByteString.cs" />

+ 30 - 0
Server/ThirdParty/Libs/KcpLib.csproj

@@ -0,0 +1,30 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.1</TargetFramework>
+  </PropertyGroup>
+
+  <PropertyGroup>
+  	<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+  	<OutputPath>..\..\..\Bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
+  	<OutputPath>..\..\..\Bin\</OutputPath>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="..\..\..\Unity\Assets\Scripts\Module\Message\Network\KCP\Kcp.cs" Link="Kcp.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\..\Unity\Assets\Plugins\x86_64\kcp.dll" Link="kcp.dll">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <None Update="libkcp.so">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+
+</Project>

BIN
Server/ThirdParty/Libs/libkcp.so


+ 8 - 0
Unity/Assets/Plugins/Android.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 89f91d9886713c242b08fc47677c6cd6
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Unity/Assets/Plugins/Android/libs.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: e683bde7d2130ef4e9cd605a119c319e
+folderAsset: yes
+timeCreated: 1529980199
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Unity/Assets/Plugins/Android/libs/armeabi-v7a.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 4b9de99f882e1334f88d3fffa436fe26
+folderAsset: yes
+timeCreated: 1529980199
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Plugins/Android/libs/armeabi-v7a/libkcp.so


+ 9 - 9
Unity/Assets/Plugins/Newtonsoft.Json.dll.meta → Unity/Assets/Plugins/Android/libs/armeabi-v7a/libkcp.so.meta

@@ -1,6 +1,6 @@
 fileFormatVersion: 2
-guid: 528015a69143a8e4cb7073828e325afd
-timeCreated: 1515924057
+guid: 8e03e31ef66b1d340bfd9de539878633
+timeCreated: 1530266293
 licenseType: Pro
 PluginImporter:
   serializedVersion: 2
@@ -11,24 +11,24 @@ PluginImporter:
   platformData:
     data:
       first:
-        Any: 
+        Android: Android
       second:
         enabled: 1
-        settings: {}
+        settings:
+          CPU: ARMv7
     data:
       first:
-        Editor: Editor
+        Any: 
       second:
         enabled: 0
-        settings:
-          DefaultValueInitialized: true
+        settings: {}
     data:
       first:
-        Windows Store Apps: WindowsStoreApps
+        Editor: Editor
       second:
         enabled: 0
         settings:
-          CPU: AnyCPU
+          DefaultValueInitialized: true
   userData: 
   assetBundleName: 
   assetBundleVariant: 

+ 9 - 0
Unity/Assets/Plugins/Android/libs/x86.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: af440bcca3a80614185db5d493411e3e
+folderAsset: yes
+timeCreated: 1529980199
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Plugins/Android/libs/x86/libkcp.so


+ 34 - 0
Unity/Assets/Plugins/Android/libs/x86/libkcp.so.meta

@@ -0,0 +1,34 @@
+fileFormatVersion: 2
+guid: 3869fe202d9b7494cbf94cbd4c9ae4c5
+timeCreated: 1530266298
+licenseType: Pro
+PluginImporter:
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  isPreloaded: 0
+  isOverridable: 0
+  platformData:
+    data:
+      first:
+        Android: Android
+      second:
+        enabled: 1
+        settings:
+          CPU: x86
+    data:
+      first:
+        Any: 
+      second:
+        enabled: 0
+        settings: {}
+    data:
+      first:
+        Editor: Editor
+      second:
+        enabled: 0
+        settings:
+          DefaultValueInitialized: true
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Plugins/Newtonsoft.Json.dll


+ 8 - 0
Unity/Assets/Plugins/x86.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 93e339b4ca47c8f4b81c2d9742800ec5
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Plugins/x86/kcp.dll


+ 122 - 0
Unity/Assets/Plugins/x86/kcp.dll.meta

@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 5163e0119c1604a43adbc28ec6fb277e
+timeCreated: 1530266315
+licenseType: Pro
+PluginImporter:
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  isPreloaded: 0
+  isOverridable: 0
+  platformData:
+    data:
+      first:
+        '': Any
+      second:
+        enabled: 0
+        settings:
+          Exclude Android: 1
+          Exclude Editor: 1
+          Exclude Linux: 0
+          Exclude Linux64: 0
+          Exclude LinuxUniversal: 0
+          Exclude OSXIntel: 0
+          Exclude OSXIntel64: 0
+          Exclude OSXUniversal: 0
+          Exclude Win: 0
+          Exclude Win64: 1
+    data:
+      first:
+        Android: Android
+      second:
+        enabled: 0
+        settings:
+          CPU: ARMv7
+    data:
+      first:
+        Any: 
+      second:
+        enabled: 0
+        settings: {}
+    data:
+      first:
+        Editor: Editor
+      second:
+        enabled: 0
+        settings:
+          CPU: x86
+          DefaultValueInitialized: true
+          OS: AnyOS
+    data:
+      first:
+        Facebook: Win
+      second:
+        enabled: 1
+        settings:
+          CPU: AnyCPU
+    data:
+      first:
+        Facebook: Win64
+      second:
+        enabled: 0
+        settings:
+          CPU: None
+    data:
+      first:
+        Standalone: Linux
+      second:
+        enabled: 1
+        settings:
+          CPU: x86
+    data:
+      first:
+        Standalone: Linux64
+      second:
+        enabled: 1
+        settings:
+          CPU: None
+    data:
+      first:
+        Standalone: LinuxUniversal
+      second:
+        enabled: 1
+        settings:
+          CPU: AnyCPU
+    data:
+      first:
+        Standalone: OSXIntel
+      second:
+        enabled: 1
+        settings:
+          CPU: AnyCPU
+    data:
+      first:
+        Standalone: OSXIntel64
+      second:
+        enabled: 1
+        settings:
+          CPU: None
+    data:
+      first:
+        Standalone: OSXUniversal
+      second:
+        enabled: 1
+        settings:
+          CPU: AnyCPU
+    data:
+      first:
+        Standalone: Win
+      second:
+        enabled: 1
+        settings:
+          CPU: AnyCPU
+    data:
+      first:
+        Standalone: Win64
+      second:
+        enabled: 0
+        settings:
+          CPU: None
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Unity/Assets/Plugins/x86_64.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 06020764b763c6647b21f6933162724f
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Plugins/x86_64/kcp.dll


+ 122 - 0
Unity/Assets/Plugins/x86_64/kcp.dll.meta

@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 803f7857fdb47b34fbe04eda49b8aa85
+timeCreated: 1530266319
+licenseType: Pro
+PluginImporter:
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  isPreloaded: 0
+  isOverridable: 0
+  platformData:
+    data:
+      first:
+        '': Any
+      second:
+        enabled: 0
+        settings:
+          Exclude Android: 1
+          Exclude Editor: 0
+          Exclude Linux: 1
+          Exclude Linux64: 1
+          Exclude LinuxUniversal: 1
+          Exclude OSXIntel: 1
+          Exclude OSXIntel64: 1
+          Exclude OSXUniversal: 1
+          Exclude Win: 1
+          Exclude Win64: 1
+    data:
+      first:
+        Android: Android
+      second:
+        enabled: 0
+        settings:
+          CPU: ARMv7
+    data:
+      first:
+        Any: 
+      second:
+        enabled: 0
+        settings: {}
+    data:
+      first:
+        Editor: Editor
+      second:
+        enabled: 1
+        settings:
+          CPU: x86_64
+          DefaultValueInitialized: true
+          OS: Windows
+    data:
+      first:
+        Facebook: Win
+      second:
+        enabled: 0
+        settings:
+          CPU: None
+    data:
+      first:
+        Facebook: Win64
+      second:
+        enabled: 1
+        settings:
+          CPU: AnyCPU
+    data:
+      first:
+        Standalone: Linux
+      second:
+        enabled: 0
+        settings:
+          CPU: None
+    data:
+      first:
+        Standalone: Linux64
+      second:
+        enabled: 0
+        settings:
+          CPU: x86_64
+    data:
+      first:
+        Standalone: LinuxUniversal
+      second:
+        enabled: 0
+        settings:
+          CPU: None
+    data:
+      first:
+        Standalone: OSXIntel
+      second:
+        enabled: 0
+        settings:
+          CPU: None
+    data:
+      first:
+        Standalone: OSXIntel64
+      second:
+        enabled: 0
+        settings:
+          CPU: AnyCPU
+    data:
+      first:
+        Standalone: OSXUniversal
+      second:
+        enabled: 0
+        settings:
+          CPU: None
+    data:
+      first:
+        Standalone: Win
+      second:
+        enabled: 0
+        settings:
+          CPU: None
+    data:
+      first:
+        Standalone: Win64
+      second:
+        enabled: 0
+        settings:
+          CPU: AnyCPU
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 24 - 5
Unity/Assets/Scripts/Base/Helper/ByteHelper.cs

@@ -62,11 +62,30 @@ namespace ETModel
 
 		public static void WriteTo(this byte[] bytes, int offset, uint num)
 		{
-			byte[] numBytes = BitConverter.GetBytes(num);
-			for (int i = 0; i < numBytes.Length; ++i)
-			{
-				bytes[offset + i] = numBytes[i];
-			}
+			bytes[offset] = (byte)(num & 0xff);
+			bytes[offset + 1] = (byte)((num & 0xff00) >> 8);
+			bytes[offset + 2] = (byte)((num & 0xff0000) >> 16);
+			bytes[offset + 3] = (byte)((num & 0xff000000) >> 24);
+		}
+		
+		public static void WriteTo(this byte[] bytes, int offset, int num)
+		{
+			bytes[offset] = (byte)(num & 0xff);
+			bytes[offset + 1] = (byte)((num & 0xff00) >> 8);
+			bytes[offset + 2] = (byte)((num & 0xff0000) >> 16);
+			bytes[offset + 3] = (byte)((num & 0xff000000) >> 24);
+		}
+		
+		public static void WriteTo(this byte[] bytes, int offset, short num)
+		{
+			bytes[offset] = (byte)(num & 0xff);
+			bytes[offset + 1] = (byte)((num & 0xff00) >> 8);
+		}
+		
+		public static void WriteTo(this byte[] bytes, int offset, ushort num)
+		{
+			bytes[offset] = (byte)(num & 0xff);
+			bytes[offset + 1] = (byte)((num & 0xff00) >> 8);
 		}
 	}
 }

+ 0 - 2
Unity/Assets/Scripts/Base/MultiMap.cs

@@ -10,8 +10,6 @@ namespace ETModel
 		// 重用list
 		private readonly Queue<List<K>> queue = new Queue<List<K>>();
 
-		private T firstKey;
-
 		public SortedDictionary<T, List<K>> GetDictionary()
 		{
 			return this.dictionary;

+ 5 - 2
Unity/Assets/Scripts/Module/Message/ErrorCode.cs

@@ -27,9 +27,12 @@ namespace ETModel
 		public const int ERR_SocketDisconnected = 202002;
 		public const int ERR_ReloadFail = 202003;
 		public const int ERR_ActorLocationNotFound = 202004;
-		public const int ERR_KcpConnectFail = 202005;
-		public const int ERR_KcpTimeout = 202006;
+		public const int ERR_KcpCantConnect = 202005;
+		public const int ERR_KcpChannelTimeout = 202006;
 		public const int ERR_KcpRemoteDisconnect = 202007;
+		public const int ERR_PeerDisconnect = 202008;
+		public const int ERR_SocketCantSend = 202009;
+		public const int ERR_SocketError = 202010;
 
 		public static bool IsRpcNeedThrowException(int error)
 		{

+ 1 - 1
Unity/Assets/Scripts/Module/Message/NetOuterComponent.cs

@@ -22,7 +22,7 @@
 	{
 		public void Awake()
 		{
-			this.Awake(NetworkProtocol.TCP);
+			this.Awake(NetworkProtocol.KCP);
 			this.MessagePacker = new ProtobufPacker();
 			this.MessageDispatcher = new ClientDispatcher();
 		}

+ 239 - 101
Unity/Assets/Scripts/Module/Message/Network/KCP/KChannel.cs

@@ -1,22 +1,20 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
-using System.Linq;
 using System.Net;
 using System.Net.Sockets;
+using System.Runtime.InteropServices;
 
 namespace ETModel
 {
 	public struct WaitSendBuffer
 	{
 		public byte[] Bytes;
-		public int Index;
 		public int Length;
 
-		public WaitSendBuffer(byte[] bytes, int index, int length)
+		public WaitSendBuffer(byte[] bytes, int length)
 		{
 			this.Bytes = bytes;
-			this.Index = index;
 			this.Length = length;
 		}
 	}
@@ -25,70 +23,68 @@ namespace ETModel
 	{
 		private Socket socket;
 
-		private KCP kcp;
+		private IntPtr kcp;
 
 		private readonly Queue<WaitSendBuffer> sendBuffer = new Queue<WaitSendBuffer>();
 
 		private bool isConnected;
+		public bool IsRecvFirstKcpMessage { get; set; }
 		private readonly IPEndPoint remoteEndPoint;
 
 		private uint lastRecvTime;
 
-		public uint Conn;
-
 		public uint RemoteConn;
-		
+
 		public Packet packet = new Packet(ushort.MaxValue);
 
 		// accept
-		public KChannel(uint conn, uint remoteConn, Socket socket, IPEndPoint remoteEndPoint, KService kService) : base(kService, ChannelType.Accept)
+		public KChannel(uint localConn, uint remoteConn, Socket socket, IPEndPoint remoteEndPoint, KService kService) : base(kService, ChannelType.Accept)
 		{
 			this.InstanceId = IdGenerater.GenerateId();
-			
-			this.Id = conn;
-			this.Conn = conn;
+
+			this.LocalConn = localConn;
 			this.RemoteConn = remoteConn;
 			this.remoteEndPoint = remoteEndPoint;
 			this.socket = socket;
-			kcp = new KCP(this.RemoteConn, this);
-			kcp.SetOutput(this.Output);
-			kcp.NoDelay(1, 10, 2, 1);  //fast
-			kcp.SetMTU(470);
-			kcp.WndSize(256, 256);
+			this.kcp = Kcp.KcpCreate(this.RemoteConn, new IntPtr(this.LocalConn));
+			Kcp.KcpSetoutput(
+				this.kcp,
+				(bytes, len, k, user) =>
+				{
+					KService.Output(bytes, len, user);
+					return len;
+				}
+			);
+			Kcp.KcpNodelay(this.kcp, 1, 10, 1, 1);
+			Kcp.KcpWndsize(this.kcp, 256, 256);
 			this.isConnected = true;
-
+			this.IsRecvFirstKcpMessage = false;
 			this.lastRecvTime = kService.TimeNow;
 		}
 
 		// connect
-		public KChannel(uint conn, Socket socket, IPEndPoint remoteEndPoint, KService kService) : base(kService, ChannelType.Connect)
+		public KChannel(uint localConn, Socket socket, IPEndPoint remoteEndPoint, KService kService) : base(kService, ChannelType.Connect)
 		{
 			this.InstanceId = IdGenerater.GenerateId();
-			
-			this.Id = conn;
-			this.Conn = conn;
-			this.socket = socket;
 
+			this.LocalConn = localConn;
+			this.socket = socket;
 			this.remoteEndPoint = remoteEndPoint;
+			this.IsRecvFirstKcpMessage = false;
 			this.lastRecvTime = kService.TimeNow;
-			this.Connect(kService.TimeNow);
+			this.Connect();
 		}
 
-		public override void Send(MemoryStream stream)
+		public uint LocalConn
 		{
-			ushort size = (ushort)(stream.Length - stream.Position);
-			byte[] bytes;
-			if (this.isConnected)
+			get
 			{
-				bytes = stream.GetBuffer();
+				return (uint)this.Id;
 			}
-			else
+			set
 			{
-				bytes = new byte[size];
-				Array.Copy(stream.GetBuffer(), stream.Position, bytes, 0, size);
+				this.Id = value;
 			}
-
-			Send(bytes, 0, size);
 		}
 
 		public override void Dispose()
@@ -100,97 +96,188 @@ namespace ETModel
 
 			base.Dispose();
 
-			for (int i = 0; i < 4; i++)
+			try
+			{
+				if (this.Error == ErrorCode.ERR_Success)
+				{
+					for (int i = 0; i < 4; i++)
+					{
+						this.Disconnect();
+					}
+				}
+			}
+			catch (Exception)
 			{
-				this.DisConnect();
 			}
 
+			if (this.kcp != IntPtr.Zero)
+			{
+				Kcp.KcpRelease(this.kcp);
+				this.kcp = IntPtr.Zero;
+			}
 			this.socket = null;
 		}
 
-		private KService GetService()
+		public override MemoryStream Stream
 		{
-			return (KService)this.service;
+			get
+			{
+				return this.packet.Stream;
+			}
 		}
 
-		public void HandleDisConnect()
+		public void Disconnect(int error)
 		{
-			this.OnError(ErrorCode.ERR_KcpRemoteDisconnect);
+			this.OnError(error);
 		}
 
-		public void HandleConnnect(uint responseConn)
+		private KService GetService()
+		{
+			return (KService)this.service;
+		}
+
+		public void HandleConnnect(uint remoteConn)
 		{
 			if (this.isConnected)
 			{
 				return;
 			}
+
+			this.RemoteConn = remoteConn;
+
+			this.kcp = Kcp.KcpCreate(this.RemoteConn, new IntPtr(this.LocalConn));
+			Kcp.KcpSetoutput(
+				this.kcp,
+				(bytes, len, k, user) =>
+				{
+					KService.Output(bytes, len, user);
+					return len;
+				}
+			);
+			Kcp.KcpNodelay(this.kcp, 1, 10, 1, 1);
+			Kcp.KcpWndsize(this.kcp, 256, 256);
+
 			this.isConnected = true;
-			this.RemoteConn = responseConn;
-			this.kcp = new KCP(responseConn, this);
-			kcp.SetOutput(this.Output);
-			kcp.NoDelay(1, 10, 2, 1);  //fast
-			kcp.SetMTU(470);
-			kcp.WndSize(256, 256);
 			this.lastRecvTime = this.GetService().TimeNow;
 
 			HandleSend();
 		}
 
-		public void HandleAccept(uint requestConn)
+		public void HandleAccept(uint remoteConn)
 		{
-			packet.Bytes.WriteTo(0, KcpProtocalType.ACK);
-			packet.Bytes.WriteTo(4, requestConn);
-			packet.Bytes.WriteTo(8, this.Conn);
-			this.socket.SendTo(packet.Bytes, 0, 12, SocketFlags.None, remoteEndPoint);
+			if (this.socket == null)
+			{
+				return;
+			}
+
+			// 如果channel已经收到过消息,则不再响应连接请求
+			if (this.IsRecvFirstKcpMessage)
+			{
+				return;
+			}
+			try
+			{
+				this.packet.Bytes.WriteTo(0, KcpProtocalType.ACK);
+				this.packet.Bytes.WriteTo(4, LocalConn);
+				this.packet.Bytes.WriteTo(8, RemoteConn);
+				this.socket.SendTo(this.packet.Bytes, 0, 12, SocketFlags.None, remoteEndPoint);
+			}
+			catch (Exception e)
+			{
+				Log.Error(e);
+				this.OnError(ErrorCode.ERR_SocketCantSend);
+			}
 		}
 
 		/// <summary>
 		/// 发送请求连接消息
 		/// </summary>
-		private void Connect(uint timeNow)
+		private void Connect()
 		{
-			packet.Bytes.WriteTo(0, KcpProtocalType.SYN);
-			packet.Bytes.WriteTo(4, this.Conn);
-			this.socket.SendTo(packet.Bytes, 0, 8, SocketFlags.None, remoteEndPoint);
+			try
+			{
+				uint timeNow = this.GetService().TimeNow;
+				this.packet.Bytes.WriteTo(0, KcpProtocalType.SYN);
+				this.packet.Bytes.WriteTo(4, this.LocalConn);
+				this.socket.SendTo(this.packet.Bytes, 0, 8, SocketFlags.None, remoteEndPoint);
 
-			// 200毫秒后再次update发送connect请求
-			this.GetService().AddToNextTimeUpdate(timeNow + 200, this.Id);
+				// 200毫秒后再次update发送connect请求
+				this.GetService().AddToUpdateNextTime(timeNow + 200, this.Id);
+			}
+			catch (Exception e)
+			{
+				Log.Error(e);
+				this.OnError(ErrorCode.ERR_SocketCantSend);
+			}
 		}
 
-		private void DisConnect()
+		private void Disconnect()
 		{
-			packet.Bytes.WriteTo(0, KcpProtocalType.FIN);
-			packet.Bytes.WriteTo(4, this.Conn);
-			packet.Bytes.WriteTo(8, this.RemoteConn);
-			//Log.Debug($"client disconnect: {this.Conn}");
-			this.socket.SendTo(packet.Bytes, 0, 12, SocketFlags.None, remoteEndPoint);
+			if (this.socket == null)
+			{
+				return;
+			}
+			try
+			{
+				this.packet.Bytes.WriteTo(0, KcpProtocalType.FIN);
+				this.packet.Bytes.WriteTo(4, this.LocalConn);
+				this.packet.Bytes.WriteTo(8, this.RemoteConn);
+				this.packet.Bytes.WriteTo(12, (uint)this.Error);
+				this.socket.SendTo(this.packet.Bytes, 0, 16, SocketFlags.None, remoteEndPoint);
+			}
+			catch (Exception e)
+			{
+				Log.Error(e);
+				this.OnError(ErrorCode.ERR_SocketCantSend);
+			}
 		}
 
-		public void Update(uint timeNow)
+		public void Update()
 		{
+			if (this.IsDisposed)
+			{
+				return;
+			}
+
+			uint timeNow = this.GetService().TimeNow;
+
 			// 如果还没连接上,发送连接请求
 			if (!this.isConnected)
 			{
-				// 5秒连接不上,报错
-				if (timeNow - this.lastRecvTime > 5 * 1000)
+				// 10秒没连接上则报错
+				if (timeNow - this.lastRecvTime > 10 * 1000)
 				{
-					this.OnError(ErrorCode.ERR_KcpConnectFail);
+					this.OnError(ErrorCode.ERR_KcpCantConnect);
 					return;
 				}
-				Connect(timeNow);
+				this.Connect();
 				return;
 			}
-			
+
 			// 超时断开连接
 			if (timeNow - this.lastRecvTime > 40 * 1000)
 			{
-				this.OnError(ErrorCode.ERR_KcpTimeout);
+				this.OnError(ErrorCode.ERR_KcpChannelTimeout);
 				return;
 			}
-			this.kcp.Update(timeNow);
 
-			uint nextUpdateTime = this.kcp.Check(timeNow);
-			this.GetService().AddToNextTimeUpdate(nextUpdateTime, this.Id);
+			try
+			{
+				Kcp.KcpUpdate(this.kcp, timeNow);
+			}
+			catch (Exception e)
+			{
+				Log.Error(e);
+				this.OnError(ErrorCode.ERR_SocketError);
+				return;
+			}
+
+
+			if (kcp != IntPtr.Zero)
+			{
+				uint nextUpdateTime = Kcp.KcpCheck(this.kcp, timeNow);
+				this.GetService().AddToUpdateNextTime(nextUpdateTime, this.Id);
+			}
 		}
 
 		private void HandleSend()
@@ -201,74 +288,125 @@ namespace ETModel
 				{
 					break;
 				}
+
 				WaitSendBuffer buffer = this.sendBuffer.Dequeue();
-				this.KcpSend(buffer.Bytes, buffer.Index, buffer.Length);
+				this.KcpSend(buffer.Bytes, buffer.Length);
 			}
 		}
 
-		public void HandleRecv(byte[] date, int length, uint timeNow)
+		public void HandleRecv(byte[] date, int length)
 		{
-			this.kcp.Input(date, 0, length);
-			this.GetService().AddToUpdate(this.Id);
+			if (this.IsDisposed)
+			{
+				return;
+			}
+
+			// 收到了kcp消息则将自己从连接状态移除
+			if (!this.IsRecvFirstKcpMessage)
+			{
+				this.GetService().RemoveFromWaitConnectChannels(this.RemoteConn);
+				this.IsRecvFirstKcpMessage = true;
+			}
+
+			Kcp.KcpInput(this.kcp, date, length);
+			this.GetService().AddToUpdateNextTime(0, this.Id);
 
 			while (true)
 			{
-				int n = kcp.PeekSize();
+				int n = Kcp.KcpPeeksize(this.kcp);
+				if (n < 0)
+				{
+					return;
+				}
 				if (n == 0)
 				{
 					this.OnError((int)SocketError.NetworkReset);
 					return;
 				}
-				this.packet.Stream.SetLength(ushort.MaxValue);
-				int count = this.kcp.Recv(this.packet.Bytes, 0, ushort.MaxValue);
+
+				byte[] buffer = this.packet.Bytes;
+				this.packet.Stream.SetLength(n);
+				this.packet.Stream.Seek(0, SeekOrigin.Begin);
+				int count = Kcp.KcpRecv(this.kcp, buffer, ushort.MaxValue);
+				if (n != count)
+				{
+					return;
+				}
 				if (count <= 0)
 				{
 					return;
 				}
 
-				lastRecvTime = timeNow;
+				lastRecvTime = this.GetService().TimeNow;
 
-				this.packet.Flag = this.packet.Bytes[0];
-				this.packet.Opcode = BitConverter.ToUInt16(this.packet.Bytes, 1);
-				this.packet.Stream.SetLength(count);
-				this.packet.Stream.Seek(Packet.Index, SeekOrigin.Begin);
 				this.OnRead(packet);
 			}
 		}
-		
-		public void Output(byte[] bytes, int count, object user)
+
+		public override void Start()
 		{
-			this.socket.SendTo(bytes, 0, count, SocketFlags.None, this.remoteEndPoint);
 		}
 
-		private void KcpSend(byte[] buffers, int index, int length)
+		public void Output(IntPtr bytes, int count)
 		{
-			this.kcp.Send(buffers, index, length);
-			this.GetService().AddToUpdate(this.Id);
+			if (this.IsDisposed)
+			{
+				return;
+			}
+			try
+			{
+				if (count == 0)
+				{
+					Log.Error($"output 0");
+					return;
+				}
+
+				Marshal.Copy(bytes, this.packet.Bytes, 0, count);
+				this.socket.SendTo(this.packet.Bytes, 0, count, SocketFlags.None, this.remoteEndPoint);
+			}
+			catch (Exception e)
+			{
+				Log.Error(e);
+				this.OnError(ErrorCode.ERR_SocketCantSend);
+			}
 		}
 
-		public override void Start()
+		private void KcpSend(byte[] buffers, int length)
 		{
+			if (this.IsDisposed)
+			{
+				return;
+			}
+			Kcp.KcpSend(this.kcp, buffers, length);
+			this.GetService().AddToUpdateNextTime(0, this.Id);
 		}
 
 		public override void Send(byte[] buffer, int index, int length)
 		{
 			if (isConnected)
 			{
-				this.KcpSend(buffer, index, length);
+				this.KcpSend(buffer, length);
 				return;
 			}
-			
-			this.sendBuffer.Enqueue(new WaitSendBuffer(buffer, index, length));
+
+			this.sendBuffer.Enqueue(new WaitSendBuffer(buffer, length));
 		}
-		
-		public override MemoryStream Stream
+
+		public override void Send(MemoryStream stream)
 		{
-			get
+			ushort size = (ushort)(stream.Length - stream.Position);
+			byte[] bytes;
+			if (this.isConnected)
 			{
-				return this.packet.Stream;
+				bytes = stream.GetBuffer();
+			}
+			else
+			{
+				bytes = new byte[size];
+				Array.Copy(stream.GetBuffer(), stream.Position, bytes, 0, size);
 			}
-		}
 
+			Send(bytes, 0, size);
+		}
 	}
 }

+ 120 - 98
Unity/Assets/Scripts/Module/Message/Network/KCP/KService.cs

@@ -15,14 +15,18 @@ namespace ETModel
 
 	public sealed class KService : AService
 	{
+		public static KService Instance { get; private set; }
+
 		private uint IdGenerater = 1000;
 
-		public uint TimeNow { get; set; }
+		public uint TimeNow { get; private set; }
 
 		private Socket socket;
 
-		private readonly Dictionary<long, KChannel> idChannels = new Dictionary<long, KChannel>();
-		
+		private readonly Dictionary<long, KChannel> localConnChannels = new Dictionary<long, KChannel>();
+
+		private readonly Dictionary<uint, KChannel> waitConnectChannels = new Dictionary<uint, KChannel>();
+
 		private readonly byte[] cache = new byte[8192];
 
 		private readonly Queue<long> removedChannels = new Queue<long>();
@@ -34,16 +38,17 @@ namespace ETModel
 		private readonly MultiMap<long, long> timeId = new MultiMap<long, long>();
 
 		private readonly List<long> timeOutTime = new List<long>();
-		
+
 		// 记录最小时间,不用每次都去MultiMap取第一个值
 		private long minTime;
-		
+
 		private EndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 0);
 
 		public KService(IPEndPoint ipEndPoint)
 		{
 			this.TimeNow = (uint)TimeHelper.ClientNow();
 			this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+			//this.socket.Blocking = false;
 			this.socket.Bind(ipEndPoint);
 #if SERVER
 			if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@@ -54,12 +59,14 @@ namespace ETModel
 				this.socket.IOControl((int)SIO_UDP_CONNRESET, new[] { Convert.ToByte(false) }, null);
 			}
 #endif
+			Instance = this;
 		}
 
 		public KService()
 		{
 			this.TimeNow = (uint)TimeHelper.ClientNow();
 			this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+			//this.socket.Blocking = false;
 			this.socket.Bind(new IPEndPoint(IPAddress.Any, 0));
 #if SERVER
 			if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@@ -70,6 +77,7 @@ namespace ETModel
 				this.socket.IOControl((int)SIO_UDP_CONNRESET, new[] { Convert.ToByte(false) }, null);
 			}
 #endif
+			Instance = this;
 		}
 
 		public override void Dispose()
@@ -78,16 +86,17 @@ namespace ETModel
 			{
 				return;
 			}
-			
+
 			base.Dispose();
 
-			foreach (KeyValuePair<long,KChannel> keyValuePair in this.idChannels)
+			foreach (KeyValuePair<long, KChannel> keyValuePair in this.localConnChannels)
 			{
 				keyValuePair.Value.Dispose();
 			}
 
 			this.socket.Close();
 			this.socket = null;
+			Instance = null;
 		}
 
 		public override void Start()
@@ -101,7 +110,7 @@ namespace ETModel
 				return;
 			}
 
-			while (this.socket.Available > 0)
+			while (socket != null && this.socket.Available > 0)
 			{
 				int messageLength = 0;
 				try
@@ -119,15 +128,17 @@ namespace ETModel
 				{
 					continue;
 				}
-
 				// accept
 				uint conn = BitConverter.ToUInt32(this.cache, 0);
 
 				// conn从1000开始,如果为1,2,3则是特殊包
+				uint remoteConn = 0;
+				uint localConn = 0;
+				KChannel kChannel = null;
 				switch (conn)
 				{
-					case KcpProtocalType.SYN:
-						// 长度!=8,不是accpet消息
+					case KcpProtocalType.SYN:  // accept
+											   // 长度!=8,不是accpet消息
 						if (messageLength != 8)
 						{
 							break;
@@ -135,129 +146,140 @@ namespace ETModel
 
 						IPEndPoint acceptIpEndPoint = (IPEndPoint)this.ipEndPoint;
 						this.ipEndPoint = new IPEndPoint(0, 0);
-						this.HandleAccept(this.cache, acceptIpEndPoint);
+
+						remoteConn = BitConverter.ToUInt32(this.cache, 4);
+
+						// 如果等待连接状态,则重新响应请求
+						if (this.waitConnectChannels.TryGetValue(remoteConn, out kChannel))
+						{
+							kChannel.HandleAccept(remoteConn);
+							break;
+						}
+
+						localConn = ++this.IdGenerater;
+						kChannel = new KChannel(localConn, remoteConn, this.socket, acceptIpEndPoint, this);
+						this.localConnChannels[kChannel.Id] = kChannel;
+						this.waitConnectChannels[remoteConn] = kChannel;
+
+						kChannel.HandleAccept(remoteConn);
+
+						this.OnAccept(kChannel);
+
 						break;
-					case KcpProtocalType.ACK:
-						// 长度!=12,不是connect消息
+					case KcpProtocalType.ACK:  // connect返回
+											   // 长度!=12,不是connect消息
 						if (messageLength != 12)
 						{
 							break;
 						}
-						this.HandleConnect(this.cache);
+						remoteConn = BitConverter.ToUInt32(this.cache, 4);
+						localConn = BitConverter.ToUInt32(this.cache, 8);
+
+						kChannel = this.GetKChannel(localConn);
+						if (kChannel != null)
+						{
+							kChannel.HandleConnnect(remoteConn);
+						}
 						break;
-					case KcpProtocalType.FIN:
-						// 长度!=12,不是DisConnect消息
-						if (messageLength != 12)
+					case KcpProtocalType.FIN:  // 断开
+											   // 长度!=12,不是DisConnect消息
+						if (messageLength != 16)
 						{
 							break;
 						}
-						this.HandleDisConnect(this.cache);
+
+						remoteConn = BitConverter.ToUInt32(this.cache, 4);
+						localConn = BitConverter.ToUInt32(this.cache, 8);
+
+						// 处理chanel
+						kChannel = this.GetKChannel(localConn);
+						if (kChannel != null)
+						{
+							if (kChannel.RemoteConn == remoteConn)
+							{
+								kChannel.Disconnect(ErrorCode.ERR_PeerDisconnect);
+							}
+						}
 						break;
-					default:
-						this.HandleRecv(this.cache, messageLength, conn);
+					default:  // 接收
+							  // 处理chanel
+						localConn = conn;
+						kChannel = this.GetKChannel(localConn);
+						if (kChannel != null)
+						{
+							kChannel.HandleRecv(this.cache, messageLength);
+						}
 						break;
 				}
 			}
 		}
 
-		private void HandleConnect(byte[] bytes)
+		public KChannel GetKChannel(long id)
 		{
-			uint requestConn = BitConverter.ToUInt32(bytes, 4);
-			uint responseConn = BitConverter.ToUInt32(bytes, 8);
-
-			KChannel kChannel;
-			if (!this.idChannels.TryGetValue(requestConn, out kChannel))
+			AChannel aChannel = this.GetChannel(id);
+			if (aChannel == null)
 			{
-				return;
+				return null;
 			}
 
-			// 处理chanel
-			kChannel.HandleConnnect(responseConn);
+			return (KChannel)aChannel;
 		}
 
-		private void HandleDisConnect(byte[] bytes)
+		public void RemoveFromWaitConnectChannels(uint remoteConn)
 		{
-			uint requestConn = BitConverter.ToUInt32(bytes, 8);
+			this.waitConnectChannels.Remove(remoteConn);
+		}
 
-			KChannel kChannel;
-			if (!this.idChannels.TryGetValue(requestConn, out kChannel))
+		public override AChannel GetChannel(long id)
+		{
+			if (this.removedChannels.Contains(id))
 			{
-				return;
+				return null;
 			}
-
-			kChannel.HandleDisConnect();
+			KChannel channel;
+			this.localConnChannels.TryGetValue(id, out channel);
+			return channel;
 		}
 
-		private void HandleRecv(byte[] bytes, int length, uint conn)
+		public static void Output(IntPtr bytes, int count, IntPtr user)
 		{
-			KChannel kChannel;
-			if (!this.idChannels.TryGetValue(conn, out kChannel))
+			if (Instance == null)
 			{
 				return;
 			}
-
-			// 处理chanel
-			kChannel.HandleRecv(bytes, length, this.TimeNow);
-		}
-
-		private void HandleAccept(byte[] bytes, IPEndPoint remoteEndPoint)
-		{
-			uint requestConn = BitConverter.ToUInt32(bytes, 4);
-
-			// 如果已经连接上,则重新响应请求
-			KChannel kChannel;
-			if (this.idChannels.TryGetValue(requestConn, out kChannel))
+			AChannel aChannel = Instance.GetChannel((uint)user);
+			if (aChannel == null)
 			{
-				kChannel.HandleAccept(requestConn);
+				Log.Error($"not found kchannel, {(uint)user}");
 				return;
 			}
 
-			kChannel = this.CreateAcceptChannel(remoteEndPoint, requestConn);
-			kChannel.HandleAccept(requestConn);
-			this.OnAccept(kChannel);
+			KChannel kChannel = aChannel as KChannel;
+			kChannel.Output(bytes, count);
 		}
 
-		private KChannel CreateAcceptChannel(IPEndPoint remoteEndPoint, uint remoteConn)
+		public override AChannel ConnectChannel(IPEndPoint remoteEndPoint)
 		{
-			KChannel channel = new KChannel(++this.IdGenerater, remoteConn, this.socket, remoteEndPoint, this);
+			uint localConn = (uint)RandomHelper.RandomNumber(1000, int.MaxValue);
 			KChannel oldChannel;
-			if (this.idChannels.TryGetValue(channel.Id, out oldChannel))
+			if (this.localConnChannels.TryGetValue(localConn, out oldChannel))
 			{
-				this.idChannels.Remove(oldChannel.Id);
+				this.localConnChannels.Remove(oldChannel.LocalConn);
 				oldChannel.Dispose();
 			}
-			this.idChannels[channel.Id] = channel;
-			return channel;
-		}
 
-		public override AChannel GetChannel(long id)
-		{
-			KChannel channel;
-			this.idChannels.TryGetValue(id, out channel);
+			KChannel channel = new KChannel(localConn, this.socket, remoteEndPoint, this);
+			this.localConnChannels[channel.LocalConn] = channel;
 			return channel;
 		}
 
-		public override AChannel ConnectChannel(IPEndPoint remoteEndPoint)
+		public void AddToUpdateNextTime(long time, long id)
 		{
-			uint conv = (uint)RandomHelper.RandomNumber(1000, int.MaxValue);
-			KChannel channel = new KChannel(conv, this.socket, remoteEndPoint, this);
-			KChannel oldChannel;
-			if (this.idChannels.TryGetValue(channel.Id, out oldChannel))
+			if (time == 0)
 			{
-				this.idChannels.Remove(oldChannel.Id);
-				oldChannel.Dispose();
+				this.updateChannels.Add(id);
+				return;
 			}
-			this.idChannels[channel.Id] = channel;
-			return channel;
-		}
-
-		public void AddToUpdate(long id)
-		{
-			this.updateChannels.Add(id);
-		}
-
-		public void AddToNextTimeUpdate(long time, long id)
-		{
 			if (time < this.minTime)
 			{
 				this.minTime = time;
@@ -268,7 +290,7 @@ namespace ETModel
 		public override void Remove(long id)
 		{
 			KChannel channel;
-			if (!this.idChannels.TryGetValue(id, out channel))
+			if (!this.localConnChannels.TryGetValue(id, out channel))
 			{
 				return;
 			}
@@ -279,19 +301,19 @@ namespace ETModel
 			this.removedChannels.Enqueue(id);
 			channel.Dispose();
 		}
-		
+
 		public override void Update()
 		{
 			this.TimeNow = (uint)TimeHelper.ClientNow();
-			
+
 			this.Recv();
-			
+
 			this.TimerOut();
 
 			foreach (long id in updateChannels)
 			{
-				KChannel kChannel;
-				if (!this.idChannels.TryGetValue(id, out kChannel))
+				KChannel kChannel = this.GetKChannel(id);
+				if (kChannel == null)
 				{
 					continue;
 				}
@@ -299,7 +321,7 @@ namespace ETModel
 				{
 					continue;
 				}
-				kChannel.Update(this.TimeNow);
+				kChannel.Update();
 			}
 			this.updateChannels.Clear();
 
@@ -310,7 +332,7 @@ namespace ETModel
 					break;
 				}
 				long id = this.removedChannels.Dequeue();
-				this.idChannels.Remove(id);
+				this.localConnChannels.Remove(id);
 			}
 		}
 
@@ -322,16 +344,16 @@ namespace ETModel
 				return;
 			}
 
-			long timeNow = this.TimeNow;
-			
+			uint timeNow = this.TimeNow;
+
 			if (timeNow < this.minTime)
 			{
 				return;
 			}
-			
+
 			this.timeOutTime.Clear();
 
-			foreach (KeyValuePair<long,List<long>> kv in this.timeId.GetDictionary())
+			foreach (KeyValuePair<long, List<long>> kv in this.timeId.GetDictionary())
 			{
 				long k = kv.Key;
 				if (k > timeNow)
@@ -341,7 +363,7 @@ namespace ETModel
 				}
 				this.timeOutTime.Add(k);
 			}
-			
+
 			foreach (long k in this.timeOutTime)
 			{
 				foreach (long v in this.timeId[k])

+ 78 - 1102
Unity/Assets/Scripts/Module/Message/Network/KCP/Kcp.cs

@@ -1,1156 +1,132 @@
-// Copyright (C) 2017 ichenq@outlook.com. All rights reserved.
-// Distributed under the terms and conditions of the MIT License.
-// See accompanying files LICENSE.
-
-using System;
-using System.Diagnostics;
-using System.Collections.Generic;
+using System;
+using System.Runtime.InteropServices;
 
 namespace ETModel
 {
-    public class KCP
-    {
-        public const int IKCP_RTO_NDL = 30;         // no delay min rto
-        public const int IKCP_RTO_MIN = 100;        // normal min rto
-        public const int IKCP_RTO_DEF = 200;
-        public const int IKCP_RTO_MAX = 60000;
-        public const int IKCP_CMD_PUSH = 81;        // cmd: push data
-        public const int IKCP_CMD_ACK = 82;         // cmd: ack
-        public const int IKCP_CMD_WASK = 83;        // cmd: window probe (ask)
-        public const int IKCP_CMD_WINS = 84;        // cmd: window size (tell)
-        public const int IKCP_ASK_SEND = 1;         // need to send IKCP_CMD_WASK
-        public const int IKCP_ASK_TELL = 2;         // need to send IKCP_CMD_WINS
-        public const int IKCP_WND_SND = 32;
-        public const int IKCP_WND_RCV = 32;
-        public const int IKCP_MTU_DEF = 1400;
-        public const int IKCP_ACK_FAST = 3;
-        public const int IKCP_INTERVAL = 100;
-        public const int IKCP_OVERHEAD = 24;
-        public const int IKCP_DEADLINK = 20;
-        public const int IKCP_THRESH_INIT = 2;
-        public const int IKCP_THRESH_MIN = 2;
-        public const int IKCP_PROBE_INIT = 7000;    // 7 secs to probe window size
-        public const int IKCP_PROBE_LIMIT = 120000; // up to 120 secs to probe window
-
-        public const int IKCP_LOG_OUTPUT = 0x1;
-        public const int IKCP_LOG_INPUT = 0x2;
-        public const int IKCP_LOG_SEND = 0x4;
-        public const int IKCP_LOG_RECV = 0x8;
-        public const int IKCP_LOG_IN_DATA = 0x10;
-        public const int IKCP_LOG_IN_ACK = 0x20;
-        public const int IKCP_LOG_IN_PROBE = 0x40;
-        public const int IKCP_LOG_IN_WINS = 0x80;
-        public const int IKCP_LOG_OUT_DATA = 0x100;
-        public const int IKCP_LOG_OUT_ACK = 0x200;
-        public const int IKCP_LOG_OUT_PROBE = 0x400;
-        public const int IKCP_LOG_OUT_WINS = 0x800;
-
-
-        // encode 8 bits unsigned int
-        public static void ikcp_encode8u(byte[] p, int offset, byte c)
-        {
-            p[offset] = c;
-        }
-
-        // decode 8 bits unsigned int
-        public static byte ikcp_decode8u(byte[] p, ref int offset)
-        {
-            return p[offset++];
-        }
-
-        // encode 16 bits unsigned int (lsb)
-        public static void ikcp_encode16u(byte[] p, int offset, ushort v)
-        {
-            p[offset] = (byte)(v & 0xFF);
-            p[offset + 1] = (byte)(v >> 8);
-        }
-
-        // decode 16 bits unsigned int (lsb)
-        public static ushort ikcp_decode16u(byte[] p, ref int offset)
-        {
-            int pos = offset;
-            offset += 2;
-            return (ushort)((ushort)p[pos] | (ushort)(p[pos + 1] << 8));
-        }
-
-        // encode 32 bits unsigned int (lsb)
-        public static void ikcp_encode32u(byte[] p, int offset, uint l)
-        {
-            p[offset] = (byte)(l & 0xFF);
-            p[offset + 1] = (byte)(l >> 8);
-            p[offset + 2] = (byte)(l >> 16);
-            p[offset + 3] = (byte)(l >> 24);
-        }
-
-        // decode 32 bits unsigned int (lsb)
-        public static uint ikcp_decode32u(byte[] p, ref int offset)
-        {
-            int pos = offset;
-            offset += 4;
-            return ((uint)p[pos] | (uint)(p[pos + 1] << 8)
-                | (uint)(p[pos + 2] << 16) | (uint)(p[pos + 3] << 24));
-        }
-
-        public static uint _imin_(uint a, uint b)
-        {
-            return a <= b ? a : b;
-        }
-
-        public static uint _imax_(uint a, uint b)
-        {
-            return a >= b ? a : b;
-        }
-
-        public static uint _ibound_(uint lower, uint middle, uint upper)
-        {
-            return _imin_(_imax_(lower, middle), upper);
-        }
-
-        public static int _itimediff(uint later, uint earlier)
-        {
-            return (int)(later - earlier);
-        }
-
-        internal class Segment: IDisposable
-        {
-            internal uint conv;
-            internal uint cmd;
-            internal uint frg;
-            internal uint wnd;
-            internal uint ts;
-            internal uint sn;
-            internal uint una;
-            internal uint resendts;
-            internal uint rto;
-            internal uint faskack;
-            internal uint xmit;
-            internal byte[] data { get; }
-
-            internal Segment(int size = 0)
-            {
-                data = new byte[size];
-            }
-
-            internal void Encode(byte[] ptr, ref int offset)
-            {
-                uint len = (uint)data.Length;
-                ikcp_encode32u(ptr, offset, conv);
-                ikcp_encode8u(ptr, offset + 4, (byte)cmd);
-                ikcp_encode8u(ptr, offset + 5, (byte)frg);
-                ikcp_encode16u(ptr, offset + 6, (ushort)wnd);
-                ikcp_encode32u(ptr, offset + 8, ts);
-                ikcp_encode32u(ptr, offset + 12, sn);
-                ikcp_encode32u(ptr, offset + 16, una);
-                ikcp_encode32u(ptr, offset + 20, len);
-                offset += IKCP_OVERHEAD;
-            }
-
-            public void Dispose()
-            {
-                this.conv = 0;
-                this.cmd = 0;
-                this.frg = 0;
-                this.wnd = 0;
-                this.ts = 0;
-                this.sn = 0;
-                this.una = 0;
-                this.resendts = 0;
-                this.rto = 0;
-                this.faskack = 0;
-                this.xmit = 0;
-            }
-        }
-
-        uint conv_;
-        uint mtu_;
-        uint mss_;
-        uint state_;
-
-        uint snd_una_;
-        uint snd_nxt_;
-        uint rcv_nxt_;
-
-        uint ts_recent_ = 0;
-        uint ts_lastack_ = 0;
-        uint ssthresh_;
-
-        int rx_rttval_;
-        int rx_srtt_;
-        int rx_rto_;
-        int rx_minrto_;
-
-        uint snd_wnd_;
-        uint rcv_wnd_;
-        uint rmt_wnd_;
-        uint cwnd_;
-        uint probe_;
-
-        uint current_;
-        uint interval_;
-        uint ts_flush_;
-        uint xmit_;
-
-        uint nrcv_buf_;
-        uint nsnd_buf_;
-        uint nrcv_que_;
-        uint nsnd_que_;
-
-        uint nodelay_;
-        uint updated_;
-        uint ts_probe_;
-        uint probe_wait_;
-        uint dead_link_;
-        uint incr_;
-
-        LinkedList<Segment> snd_queue_;
-        LinkedList<Segment> rcv_queue_;
-        LinkedList<Segment> snd_buf_;
-        LinkedList<Segment> rcv_buf_;
-
-        uint[] acklist_;
-        uint ackcount_;
-        uint ackblock_;
-
-        byte[] buffer_;
-        object user_;
-
-        int fastresend_;
-        int nocwnd_;
-
-        public delegate void OutputDelegate(byte[] data, int size, object user);
-        OutputDelegate output_;
-
-        // create a new kcp control object, 'conv' must equal in two endpoint
-        // from the same connection. 'user' will be passed to the output callback
-        // output callback can be setup like this: 'kcp->output = my_udp_output'
-        public KCP(uint conv, object user)
-        {
-            Debug.Assert(BitConverter.IsLittleEndian); // we only support little endian device
-
-            user_ = user;
-            conv_ = conv;
-            snd_wnd_ = IKCP_WND_SND;
-            rcv_wnd_ = IKCP_WND_RCV;
-            rmt_wnd_ = IKCP_WND_RCV;
-            mtu_ = IKCP_MTU_DEF;
-            mss_ = mtu_ - IKCP_OVERHEAD;
-            rx_rto_ = IKCP_RTO_DEF;
-            rx_minrto_ = IKCP_RTO_MIN;
-            interval_ = IKCP_INTERVAL;
-            ts_flush_ = IKCP_INTERVAL;
-            ssthresh_ = IKCP_THRESH_INIT;
-            dead_link_ = IKCP_DEADLINK;
-            buffer_ = new byte[(mtu_ + IKCP_OVERHEAD) * 3];
-            snd_queue_ = new LinkedList<Segment>();
-            rcv_queue_ = new LinkedList<Segment>();
-            snd_buf_ = new LinkedList<Segment>();
-            rcv_buf_ = new LinkedList<Segment>();
-        }
-
-        // release kcp control object
-        public void Release()
-        {
-            snd_buf_.Clear();
-            rcv_buf_.Clear();
-            snd_queue_.Clear();
-            rcv_queue_.Clear();
-            nrcv_buf_ = 0;
-            nsnd_buf_ = 0;
-            nrcv_que_ = 0;
-            nsnd_que_ = 0;
-            ackblock_ = 0;
-            ackcount_ = 0;
-            buffer_ = null;
-            acklist_ = null;
-        }
-
-        // set output callback, which will be invoked by kcp
-        public void SetOutput(OutputDelegate output)
-        {
-            output_ = output;
-        }
-
-        // user/upper level recv: returns size, returns below zero for EAGAIN
-        public int Recv(byte[] buffer, int offset, int len)
-        {
-            int ispeek = (len < 0 ? 1 : 0);
-            int recover = 0;
-
-            if (rcv_queue_.Count == 0)
-                return -1;
-
-            if (len < 0)
-                len = -len;
-
-            int peeksize = PeekSize();
-            if (peeksize < 0)
-                return -2;
-
-            if (peeksize > len)
-                return -3;
-
-            if (nrcv_que_ >= rcv_wnd_)
-                recover = 1;
-
-            // merge fragment
-            len = 0;
-            LinkedListNode<Segment> next = null;
-            for (var node = rcv_queue_.First; node != null; node = next)
-            {
-                int fragment = 0;
-                var seg = node.Value;
-                next = node.Next;
-                
-                if (buffer != null)
-                {
-                    Buffer.BlockCopy(seg.data, 0, buffer, offset, seg.data.Length);
-                    offset += seg.data.Length;
-                }
-                len += seg.data.Length;
-                fragment = (int)seg.frg;
-
-                Log(IKCP_LOG_RECV, "recv sn={0}", seg.sn);
-
-                if (ispeek == 0)
-                {
-                    rcv_queue_.Remove(node);
-                    nrcv_que_--;
-                }
-
-                if (fragment == 0)
-                    break;
-            }
-
-            Debug.Assert(len == peeksize);
-
-            // move available data from rcv_buf -> rcv_queue
-            while (rcv_buf_.Count > 0)
-            {
-                var node = rcv_buf_.First;
-                var seg = node.Value;
-                if (seg.sn == rcv_nxt_ && nrcv_que_ < rcv_wnd_)
-                {
-                    rcv_buf_.Remove(node);
-                    nrcv_buf_--;
-                    rcv_queue_.AddLast(node);
-                    nrcv_que_++;
-                    rcv_nxt_++;
-                }
-                else
-                {
-                    break;
-                }
-            }
-
-            // fast recover
-            if (nrcv_que_ < rcv_wnd_ && recover != 0)
-            {
-                // ready to send back IKCP_CMD_WINS in ikcp_flush
-                // tell remote my window size
-                probe_ |= IKCP_ASK_TELL;
-            }
-
-            return len;
-        }
-
-        // check the size of next message in the recv queue
-        public int PeekSize()
-        {
-            if (rcv_queue_.Count == 0)
-                return -1;
-
-            var node = rcv_queue_.First;
-            var seg = node.Value;
-            if (seg.frg == 0)
-                return seg.data.Length;
-
-            if (nrcv_que_ < seg.frg + 1)
-                return -1;
-
-            int length = 0;
-            for (node = rcv_queue_.First; node != null; node = node.Next)
-            {
-                seg = node.Value;
-                length += seg.data.Length;
-                if (seg.frg == 0)
-                    break;
-            }
-            return length;
-        }
-
-        // user/upper level send, returns below zero for error
-        public int Send(byte[] buffer, int offset, int len)
-        {
-            Debug.Assert(mss_ > 0);
-            if (len < 0)
-                return -1;
 
-            //
-            // not implement streaming mode here as ikcp.c
-            //
+    
+    public delegate int kcp_output(IntPtr buf, int len, IntPtr kcp, IntPtr user);
 
-            int count = 0;
-            if (len <= (int)mss_)
-                count = 1;
-            else
-                count = (len + (int)mss_ - 1) / (int)mss_;
-
-            if (count > 255) // maximum value `frg` can present
-                return -2;
-
-            if (count == 0)
-                count = 1;
-
-            // fragment
-            for (int i = 0; i < count; i++)
-            {
-                int size = len > (int)mss_ ? (int)mss_ : len;
-                var seg = new Segment(size);
-                if (buffer != null && len > 0)
-                {
-                    Buffer.BlockCopy(buffer, offset, seg.data, 0, size);
-                    offset += size;
-                }
-                seg.frg = (uint)(count - i - 1);
-                snd_queue_.AddLast(seg);
-                nsnd_que_++;
-                len -= size;
-            }
-            return 0;
-        }
-
-        // parse ack
-        void UpdateACK(int rtt)
-        {
-            if (rx_srtt_ == 0)
-            {
-                rx_srtt_ = rtt;
-                rx_rttval_ = rtt / 2;
-            }
-            else
-            {
-                int delta = rtt - rx_srtt_;
-                if (delta < 0)
-                    delta = -delta;
-
-                rx_rttval_ = (3 * rx_rttval_ + delta) / 4;
-                rx_srtt_ = (7 * rx_srtt_ + rtt) / 8;
-                if (rx_srtt_ < 1)
-                    rx_srtt_ = 1;
-            }
-
-            var rto = rx_srtt_ + _imax_(interval_, (uint)(4 * rx_rttval_));
-            rx_rto_ = (int)_ibound_((uint)rx_minrto_, (uint)rto, IKCP_RTO_MAX);
-        }
-
-        void ShrinkBuf()
-        {
-            var node = snd_buf_.First;
-            if (node != null)
-            {
-                var seg = node.Value;
-                snd_una_ = seg.sn;
-            }
-            else
-            {
-                snd_una_ = snd_nxt_;
-            }
-        }
-
-        void ParseACK(uint sn)
-        {
-            if (_itimediff(sn, snd_una_) < 0 || _itimediff(sn, snd_nxt_) >= 0)
-                return;
-
-            LinkedListNode<Segment> next = null;
-            for (var node = snd_buf_.First; node != null; node = next)
-            {
-                var seg = node.Value;
-                next = node.Next;
-                if (sn == seg.sn)
-                {
-                    snd_buf_.Remove(node);
-                    nsnd_buf_--;
-                    break;
-                }
-                if (_itimediff(sn, seg.sn) < 0)
-                    break;
-            }
-        }
-
-        void ParseUNA(uint una)
-        {
-            LinkedListNode<Segment> next = null;
-            for (var node = snd_buf_.First; node != null; node = next)
-            {
-                var seg = node.Value;
-                next = node.Next;
-                if (_itimediff(una, seg.sn) > 0)
-                {
-                    snd_buf_.Remove(node);
-                    nsnd_buf_--;
-                }
-                else
-                {
-                    break;
-                }
-            }
-        }
-
-        void ParseFastACK(uint sn)
-        {
-            if (_itimediff(sn, snd_una_) < 0 || _itimediff(sn, snd_nxt_) >= 0)
-                return;
-
-            LinkedListNode<Segment> next = null;
-            for (var node = snd_buf_.First; node != null; node = next)
-            {
-                var seg = node.Value;
-                next = node.Next;
-                if (_itimediff(sn, seg.sn) < 0)
-                {
-                    break;
-                }
-                else if (sn != seg.sn)
-                {
-                    seg.faskack++;
-                }
-            }
-        }
+    public class Kcp
+    {
+#if UNITY_IPHONE && !UNITY_EDITOR
+        const string KcpDLL = "__Internal";
+#else
+        const string KcpDLL = "kcp";
+#endif
 
-        // ack append
-        void ACKPush(uint sn, uint ts)
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern uint ikcp_check(IntPtr kcp, uint current);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern IntPtr ikcp_create(uint conv, IntPtr user);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern void ikcp_flush(IntPtr kcp);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern uint ikcp_getconv(IntPtr ptr);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern int ikcp_input(IntPtr kcp, byte[] data, long size);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern int ikcp_nodelay(IntPtr kcp, int nodelay, int interval, int resend, int nc);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern int ikcp_peeksize(IntPtr kcp);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern int ikcp_recv(IntPtr kcp, byte[] buffer, int len);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern void ikcp_release(IntPtr kcp);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern int ikcp_send(IntPtr kcp, byte[] buffer, int len);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern void ikcp_setminrto(IntPtr ptr, int minrto);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern int ikcp_setmtu(IntPtr kcp, int mtu);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern void ikcp_setoutput(IntPtr kcp, kcp_output output);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern void ikcp_update(IntPtr kcp, uint current);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern int ikcp_waitsnd(IntPtr kcp);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        public static extern int ikcp_wndsize(IntPtr kcp, int sndwnd, int rcvwnd);
+        
+        public static uint KcpCheck(IntPtr kcp, uint current)
         {
-            var newsize = ackcount_ + 1;
-            if (newsize > ackblock_)
-            {
-                uint newblock = 8;
-                for (; newblock < newsize; newblock <<= 1)
-                    ;
-
-                var acklist = new uint[newblock * 2];
-                if (acklist_ != null)
-                {
-                    for (var i = 0; i < ackcount_; i++)
-                    {
-                        acklist[i * 2] = acklist_[i * 2];
-                        acklist[i * 2 + 1] = acklist_[i * 2 + 1];
-                    }
-                }
-                acklist_ = acklist;
-                ackblock_ = newblock;
-            }
-            acklist_[ackcount_ * 2] = sn;
-            acklist_[ackcount_ * 2 + 1] = ts;
-            ackcount_++;
+            return ikcp_check(kcp, current);
         }
-
-        void ACKGet(int pos, ref uint sn, ref uint ts)
+        
+        public static IntPtr KcpCreate(uint conv, IntPtr user)
         {
-            sn = acklist_[pos * 2];
-            ts = acklist_[pos * 2 + 1];
-        }
-
-        // parse data
-        void ParseData(Segment newseg)
-        {
-            uint sn = newseg.sn;
-            int repeat = 0;
-
-            if (_itimediff(sn, rcv_nxt_ + rcv_wnd_) >= 0 ||
-                _itimediff(sn, rcv_nxt_) < 0)
-            {
-                return;
-            }
-
-            LinkedListNode<Segment> node = null;
-            LinkedListNode<Segment> prev = null;
-            for (node = rcv_buf_.Last; node != null; node = prev)
-            {
-                var seg = node.Value;
-                prev = node.Previous;
-                if (seg.sn == sn)
-                {
-                    repeat = 1;
-                    break;
-                }
-                if (_itimediff(sn, seg.sn) > 0) 
-                {
-                    break;
-                }
-            }
-            if (repeat == 0)
-            {
-                if (node != null)
-                {
-                    rcv_buf_.AddAfter(node, newseg);
-                }
-                else
-                {
-                    rcv_buf_.AddFirst(newseg);
-                }
-                nrcv_buf_++;
-            }
-
-            // move available data from rcv_buf -> rcv_queue
-            while (rcv_buf_.Count > 0)
-            {
-                node = rcv_buf_.First;
-                var seg = node.Value;
-                if (seg.sn == rcv_nxt_ && nrcv_que_ < rcv_wnd_)
-                {
-                    rcv_buf_.Remove(node);
-                    nrcv_buf_--;
-                    rcv_queue_.AddLast(node);
-                    nrcv_que_++;
-                    rcv_nxt_++;
-                }
-                else
-                {
-                    break;
-                }
-            }
-        }
-
-        // when you received a low level packet (eg. UDP packet), call it
-        public int Input(byte[] data, int offset, int size)
-        {
-            uint maxack = 0;
-            int flag = 0;
-
-            Log(IKCP_LOG_INPUT, "[RI] {0} bytes", size);
-
-            if (data == null || size < IKCP_OVERHEAD)
-                return -1;
-
-            while (true)
-            {
-                if (size < IKCP_OVERHEAD)
-                    break;
-
-                uint conv = ikcp_decode32u(data, ref offset);
-                //if (conv_ != conv)
-                //    return -1;
-                uint cmd = ikcp_decode8u(data, ref offset);
-                uint frg = ikcp_decode8u(data, ref offset);
-                uint wnd = ikcp_decode16u(data, ref offset);
-                uint ts = ikcp_decode32u(data, ref offset);
-                uint sn = ikcp_decode32u(data, ref offset);
-                uint una = ikcp_decode32u(data, ref offset);
-                uint len = ikcp_decode32u(data, ref offset);
-
-                size -= IKCP_OVERHEAD;
-                if (size < len)
-                    return -2;
-
-                if (cmd != IKCP_CMD_PUSH && cmd != IKCP_CMD_ACK &&
-                    cmd != IKCP_CMD_WASK && cmd != IKCP_CMD_WINS)
-                    return -3;
-
-                rmt_wnd_ = wnd;
-                ParseUNA(una);
-                ShrinkBuf();
-
-                if (cmd == IKCP_CMD_ACK)
-                {
-                    if (_itimediff(current_, ts) >= 0)
-                    {
-                        UpdateACK(_itimediff(current_, ts));
-                    }
-                    ParseACK(sn);
-                    ShrinkBuf();
-                    if (flag == 0)
-                    {
-                        flag = 1;
-                        maxack = sn;
-                    }
-                    else
-                    {
-                        if (_itimediff(sn, maxack) > 0)
-                        {
-                            maxack = sn;
-                        }
-                    }
-                    Log(IKCP_LOG_IN_DATA, "input ack: sn={0} rtt={1} rto={2}",
-                        sn, _itimediff(current_, ts), rx_rto_);
-                }
-                else if (cmd == IKCP_CMD_PUSH)
-                {
-                    Log(IKCP_LOG_IN_DATA, "input psh: sn={0} ts={1}", sn, ts);
-                    if (_itimediff(sn, rcv_nxt_ + rcv_wnd_) < 0)
-                    {
-                        ACKPush(sn, ts);
-                        if (_itimediff(sn, rcv_nxt_) >= 0)
-                        {
-                            var seg = new Segment((int)len);
-                            seg.conv = conv;
-                            seg.cmd = cmd;
-                            seg.frg = frg;
-                            seg.wnd = wnd;
-                            seg.ts = ts;
-                            seg.sn = sn;
-                            seg.una = una;
-                            if (len > 0)
-                            {
-                                Buffer.BlockCopy(data, offset, seg.data, 0, (int)len);
-                            }
-                            ParseData(seg);
-                        }
-                    }
-                }
-                else if (cmd == IKCP_CMD_WASK)
-                {
-                    // ready to send back IKCP_CMD_WINS in ikcp_flush
-                    // tell remote my window size
-                    probe_ |= IKCP_ASK_TELL;
-                    Log(IKCP_LOG_IN_PROBE, "input probe");
-                }
-                else if (cmd == IKCP_CMD_WINS)
-                {
-                    // do nothing
-                    Log(IKCP_LOG_IN_WINS, "input wins: {0}", wnd);
-                }
-                else
-                {
-                    return -3;
-                }
-
-                offset += (int)len;
-                size -= (int)len;
-            }
-
-            if (flag != 0)
-            {
-                ParseFastACK(maxack);
-            }
-
-            uint unack = snd_una_;
-            if (_itimediff(snd_una_, unack) > 0)
-            {
-                if (cwnd_ < rmt_wnd_)
-                {
-                    if (cwnd_ < ssthresh_)
-                    {
-                        cwnd_++;
-                        incr_ += mss_;
-                    }
-                    else
-                    {
-                        if (incr_ < mss_)
-                            incr_ = mss_;
-                        incr_ += (mss_ * mss_) / incr_ + (mss_ / 16);
-                        if ((cwnd_ + 1) * mss_ <= incr_)
-                            cwnd_++;
-                    }
-                    if (cwnd_ > rmt_wnd_)
-                    {
-                        cwnd_ = rmt_wnd_;
-                        incr_ = rmt_wnd_ * mss_;
-                    }
-                }
-            }
-
-            return 0;
+            return ikcp_create(conv, user);
         }
 
-        int WndUnused()
+        public static void KcpFlush(IntPtr kcp)
         {
-            if (nrcv_que_ < rcv_wnd_)
-                return (int)(rcv_wnd_ - nrcv_que_);
-            return 0;
+            ikcp_flush(kcp);
         }
 
-        // flush pending data
-        void Flush()
+        public static uint KcpGetconv(IntPtr ptr)
         {
-            int change = 0;
-            int lost = 0;
-            int offset = 0;
-
-            // 'ikcp_update' haven't been called. 
-            if (updated_ == 0)
-                return;
-
-            var seg = new Segment
-            {
-                conv = conv_,
-                cmd = IKCP_CMD_ACK,
-                wnd = (uint)WndUnused(),
-                una = rcv_nxt_,
-            };
-
-            // flush acknowledges
-            int count = (int)ackcount_;
-            for (int i = 0; i < count; i++)
-            {
-                if ((offset + IKCP_OVERHEAD) > mtu_)
-                {
-                    output_(buffer_, offset, user_);
-                    offset = 0;
-                }
-                ACKGet(i, ref seg.sn, ref seg.ts);
-                seg.Encode(buffer_, ref offset);
-            }
-
-            ackcount_ = 0;
-
-            // probe window size (if remote window size equals zero)
-            if (rmt_wnd_ == 0)
-            {
-                if (probe_wait_ == 0)
-                {
-                    probe_wait_ = IKCP_PROBE_INIT;
-                    ts_probe_ = current_ + probe_wait_;
-                }
-                else
-                {
-                    if (_itimediff(current_, ts_probe_) >= 0)
-                    {
-                        if (probe_wait_ < IKCP_PROBE_INIT)
-                            probe_wait_ = IKCP_PROBE_INIT;
-                        probe_wait_ += probe_wait_ / 2;
-                        if (probe_wait_ > IKCP_PROBE_LIMIT)
-                            probe_wait_ = IKCP_PROBE_LIMIT;
-                        ts_probe_ = current_ + probe_wait_;
-                        probe_ |= IKCP_ASK_SEND;
-                    }
-                }
-            }
-            else
-            {
-                ts_probe_ = 0;
-                probe_wait_ = 0;
-            }
-
-            // flush window probing commands
-            if ((probe_ & IKCP_ASK_SEND) > 0)
-            {
-                seg.cmd = IKCP_CMD_WASK;
-                if ((offset + IKCP_OVERHEAD) > mtu_)
-                {
-                    output_(buffer_, offset, user_);
-                    offset = 0;
-                }
-                seg.Encode(buffer_, ref offset);
-            }
-
-            // flush window probing commands
-            if ((probe_ & IKCP_ASK_TELL) > 0)
-            {
-                seg.cmd = IKCP_CMD_WINS;
-                if ((offset + IKCP_OVERHEAD) > mtu_)
-                {
-                    output_(buffer_, offset, user_);
-                    offset = 0;
-                }
-                seg.Encode(buffer_, ref offset);
-            }
-
-            probe_ = 0;
-
-            // calculate window size
-            uint cwnd = _imin_(snd_wnd_, rmt_wnd_);
-            if (nocwnd_ == 0)
-                cwnd = _imin_(cwnd_, cwnd);
-
-            // move data from snd_queue to snd_buf
-            while (_itimediff(snd_nxt_, snd_una_ + cwnd) < 0)
-            {
-                if (snd_queue_.Count == 0)
-                    break;
-
-                var node = snd_queue_.First;
-                var newseg = node.Value;
-                snd_queue_.Remove(node);
-                snd_buf_.AddLast(node);
-                nsnd_que_--;
-                nsnd_buf_++;
-
-                newseg.conv = conv_;
-                newseg.cmd = IKCP_CMD_PUSH;
-                newseg.wnd = seg.wnd;
-                newseg.ts = current_;
-                newseg.sn = snd_nxt_++;
-                newseg.una = rcv_nxt_;
-                newseg.resendts = current_;
-                newseg.rto = (uint)rx_rto_;
-                newseg.faskack = 0;
-                newseg.xmit = 0;
-            }
-
-            // calculate resent
-            uint resent = (fastresend_ > 0 ? (uint)fastresend_ : 0xffffffff);
-            uint rtomin = (nodelay_ == 0 ? (uint)(rx_rto_ >> 3) : 0);
-
-            // flush data segments
-            for (var node = snd_buf_.First; node != null; node = node.Next)
-            {
-                var segment = node.Value;
-                int needsend = 0;
-                if (segment.xmit == 0)
-                {
-                    needsend = 1;
-                    segment.xmit++;
-                    segment.rto = (uint)rx_rto_;
-                    segment.resendts = current_ + segment.rto + rtomin;
-                }
-                else if (_itimediff(current_, segment.resendts) >= 0)
-                {
-                    needsend = 1;
-                    segment.xmit++;
-                    xmit_++;
-                    if (nodelay_ == 0)
-                        segment.rto += (uint)rx_rto_;
-                    else
-                        segment.rto += (uint)rx_rto_ / 2;
-                    segment.resendts = current_ + segment.rto;
-                    lost = 1;
-                }
-                else if (segment.faskack >= resent)
-                {
-                    needsend = 1;
-                    segment.xmit++;
-                    segment.faskack = 0;
-                    segment.resendts = current_ + segment.rto;
-                    change++;
-                }
-
-                if (needsend > 0)
-                {
-                    segment.ts = current_;
-                    segment.wnd = seg.wnd;
-                    segment.una = rcv_nxt_;
-
-                    int need = IKCP_OVERHEAD;
-                    if (segment.data != null)
-                        need += segment.data.Length;
-
-                    if (offset + need > mtu_)
-                    {
-                        output_(buffer_, offset, user_);
-                        offset = 0;
-                    }
-                    segment.Encode(buffer_, ref offset);
-                    if (segment.data.Length > 0)
-                    {
-                        Buffer.BlockCopy(segment.data, 0, buffer_, offset, segment.data.Length);
-                        offset += segment.data.Length;
-                    }
-                    if (segment.xmit >= dead_link_)
-                        state_ = 0xffffffff;
-                }
-            }
-
-            // flush remain segments
-            if (offset > 0)
-            {
-                output_(buffer_, offset, user_);
-                offset = 0;
-            }
-
-            // update ssthresh
-            if (change > 0)
-            {
-                uint inflight = snd_nxt_ - snd_una_;
-                ssthresh_ = inflight / 2;
-                if (ssthresh_ < IKCP_THRESH_MIN)
-                    ssthresh_ = IKCP_THRESH_MIN;
-                cwnd_ = ssthresh_ + resent;
-                incr_ = cwnd_ * mss_;
-            }
-
-            if (lost > 0)
-            {
-                ssthresh_ = cwnd / 2;
-                if (ssthresh_ < IKCP_THRESH_MIN)
-                    ssthresh_ = IKCP_THRESH_MIN;
-                cwnd_ = 1;
-                incr_ = mss_;
-            }
-
-            if (cwnd_ < 1)
-            {
-                cwnd_ = 1;
-                incr_ = mss_;
-            }
+            return ikcp_getconv(ptr);
         }
 
-        // update state (call it repeatedly, every 10ms-100ms), or you can ask 
-        // ikcp_check when to call it again (without ikcp_input/_send calling).
-        // 'current' - current timestamp in millisec. 
-        public void Update(uint current)
+        public static int KcpInput(IntPtr kcp, byte[] data, long size)
         {
-            current_ = current;
-            if (updated_ == 0)
-            {
-                updated_ = 1;
-                ts_flush_ = current;
-            }
-
-            int slap = _itimediff(current_, ts_flush_);
-            if (slap >= 10000 || slap < -10000)
-            {
-                ts_flush_ = current;
-                slap = 0;
-            }
-
-            if (slap >= 0)
-            {
-                ts_flush_ += interval_;
-                if (_itimediff(current_, ts_flush_) >= 0)
-                    ts_flush_ = current_ + interval_;
-
-                Flush();
-            }
+            return ikcp_input(kcp, data, size);
         }
 
-        // Determine when should you invoke ikcp_update:
-        // returns when you should invoke ikcp_update in millisec, if there 
-        // is no ikcp_input/_send calling. you can call ikcp_update in that
-        // time, instead of call update repeatly.
-        // Important to reduce unnacessary ikcp_update invoking. use it to 
-        // schedule ikcp_update (eg. implementing an epoll-like mechanism, 
-        // or optimize ikcp_update when handling massive kcp connections)
-        public uint Check(uint current)
+        public static int KcpNodelay(IntPtr kcp, int nodelay, int interval, int resend, int nc)
         {
-            uint ts_flush = ts_flush_;
-            int tm_flush = 0x7fffffff;
-            int tm_packet = 0x7fffffff;
-
-            if (updated_ == 0)
-                return current;
-
-            if (_itimediff(current, ts_flush) >= 10000 || 
-                _itimediff(current, ts_flush) < -10000)
-            {
-                ts_flush = current;
-            }
-
-            if (_itimediff(current, ts_flush) >= 0)
-                return current;
-
-            tm_flush = _itimediff(ts_flush, current);
-
-            for (var node = snd_buf_.First; node != null; node = node.Next)
-            {
-                var seg = node.Value;
-                int diff = _itimediff(seg.resendts, current);
-                if (diff <= 0)
-                    return current;
-
-                if (diff < tm_packet)
-                    tm_packet = diff;
-            }
-
-            uint minimal = (uint)(tm_packet < tm_flush ? tm_packet : tm_flush);
-            if (minimal >= interval_)
-                minimal = interval_;
-
-            return current + minimal;
+            return ikcp_nodelay(kcp, nodelay, interval, resend, nc);
         }
 
-        // change MTU size, default is 1400
-        public int SetMTU(int mtu)
+        public static int KcpPeeksize(IntPtr kcp)
         {
-            if (mtu < 50 || mtu < IKCP_OVERHEAD)
-                return -1;
-
-            var buffer = new byte[(mtu + IKCP_OVERHEAD) * 3];
-            mtu_ = (uint)mtu;
-            mss_ = mtu_ - IKCP_OVERHEAD;
-            buffer_ = buffer;
-            return 0;
+            return ikcp_peeksize(kcp);
         }
 
-        public int Interval(int interval)
+        public static int KcpRecv(IntPtr kcp, byte[] buffer, int len)
         {
-            if (interval > 5000)
-                interval = 5000;
-            else if (interval < 10)
-                interval = 10;
-
-            interval_ = (uint)interval;
-            return 0;
+            return ikcp_recv(kcp, buffer, len);
         }
 
-        // fastest: ikcp_nodelay(kcp, 1, 20, 2, 1)
-        // nodelay: 0:disable(default), 1:enable
-        // interval: internal update timer interval in millisec, default is 100ms 
-        // resend: 0:disable fast resend(default), 1:enable fast resend
-        // nc: 0:normal congestion control(default), 1:disable congestion control
-        public int NoDelay(int nodelay, int interval, int resend, int nc)
+        public static void KcpRelease(IntPtr kcp)
         {
-            if (nodelay >= 0)
-            {
-                nodelay_ = (uint)nodelay;
-                if (nodelay > 0)
-                {
-                    rx_minrto_ = IKCP_RTO_NDL;
-                }
-                else
-                {
-                    rx_minrto_ = IKCP_RTO_MIN;
-                }
-            }
-            if (interval >= 0)
-            {
-                if (interval > 5000)
-                    interval = 5000;
-                else if (interval < 10)
-                    interval = 10;
-
-                interval_ = (uint)interval;
-            }
-
-            if (resend >= 0)
-                fastresend_ = resend;
-
-            if (nc >= 0)
-                nocwnd_ = nc;
-
-            return 0;
+            ikcp_release(kcp);
         }
 
-        // set maximum window size: sndwnd=32, rcvwnd=32 by default
-        public int WndSize(int sndwnd, int rcvwnd)
+        public static int KcpSend(IntPtr kcp, byte[] buffer, int len)
         {
-            if (sndwnd > 0)
-                snd_wnd_ = (uint)sndwnd;
-            if (rcvwnd > 0)
-                rcv_wnd_ = (uint)rcvwnd;
-            return 0;
+            return ikcp_send(kcp, buffer, len);
         }
 
-        // get how many packet is waiting to be sent
-        public int WaitSnd()
+        public static void KcpSetminrto(IntPtr ptr, int minrto)
         {
-            return (int)(nsnd_buf_ + nsnd_que_);
+            ikcp_setminrto(ptr, minrto);
         }
 
-        // read conv
-        public uint GetConv()
+        public static int KcpSetmtu(IntPtr kcp, int mtu)
         {
-            return conv_;
+            return ikcp_setmtu(kcp, mtu);
         }
 
-        public uint GetState()
+        public static void KcpSetoutput(IntPtr kcp, kcp_output output)
         {
-            return state_;
+            ikcp_setoutput(kcp, output);
         }
 
-        public void SetMinRTO(int minrto)
+        public static void KcpUpdate(IntPtr kcp, uint current)
         {
-            rx_minrto_ = minrto;
+            ikcp_update(kcp, current);
         }
 
-        public void SetFastResend(int resend)
+        public static int KcpWaitsnd(IntPtr kcp)
         {
-            fastresend_ = resend;
+            return ikcp_waitsnd(kcp);
         }
 
-        void Log(int mask, string format, params object[] args)
+        public static int KcpWndsize(IntPtr kcp, int sndwnd, int rcvwnd)
         {
-            // Console.WriteLine(mask + String.Format(format, args));
+            return ikcp_wndsize(kcp, sndwnd, rcvwnd);
         }
     }
 }
+

+ 8 - 12
Unity/Assets/Scripts/Module/Message/Network/TCP/PacketParser.cs

@@ -11,11 +11,12 @@ namespace ETModel
 
 	public class Packet
 	{
+		public const int SizeLength = 2;
 		public const int MinSize = 3;
 		public const int MaxSize = 60000;
-		public const int FlagIndex = 0;
-		public const int OpcodeIndex = 1;
-		public const int Index = 3;
+		public const int FlagIndex = 2;
+		public const int OpcodeIndex = 3;
+		public const int MessageIndex = 5;
 
 		/// <summary>
 		/// 只读,不允许修改
@@ -49,7 +50,6 @@ namespace ETModel
 		private ushort packetSize;
 		private ParserState state;
 		public readonly Packet packet = new Packet(ushort.MaxValue);
-		private readonly byte[] cache = new byte[2];
 		private bool isOK;
 
 		public PacketParser(CircularBuffer buffer)
@@ -92,15 +92,11 @@ namespace ETModel
 						}
 						else
 						{
-							this.buffer.Read(this.cache, 0, 1);
-							this.packet.Flag = this.cache[0];
-							this.buffer.Read(this.cache, 0, 2);
-							this.packet.Opcode = BitConverter.ToUInt16(this.cache, 0);
-							
 							this.packet.Stream.Seek(0, SeekOrigin.Begin);
-							this.packet.Stream.SetLength(this.packetSize - Packet.Index);
-							this.buffer.Read(this.packet.Stream.GetBuffer(), 0, this.packetSize - Packet.Index);
-							
+							this.packet.Stream.SetLength(this.packetSize + Packet.SizeLength);
+							byte[] bytes = this.packet.Stream.GetBuffer();
+							bytes.WriteTo(0, this.packetSize);
+							this.buffer.Read(bytes, Packet.SizeLength, this.packetSize);
 							this.isOK = true;
 							this.state = ParserState.PacketSize;
 							finish = true;

+ 0 - 5
Unity/Assets/Scripts/Module/Message/Network/TCP/TChannel.cs

@@ -100,8 +100,6 @@ namespace ETModel
 			{
 				throw new Exception("TChannel已经被Dispose, 不能发送消息");
 			}
-			byte[] sizeBuffer = BitConverter.GetBytes(length);
-			this.sendBuffer.Write(sizeBuffer, 0, sizeBuffer.Length);
 			this.sendBuffer.Write(buffer, index, length);
 
 			if(!this.isSending)
@@ -117,9 +115,6 @@ namespace ETModel
 				throw new Exception("TChannel已经被Dispose, 不能发送消息");
 			}
 
-			ushort size = (ushort)(stream.Length - stream.Position);
-			byte[] sizeBuffer = BitConverter.GetBytes(size);
-			this.sendBuffer.Write(sizeBuffer, 0, sizeBuffer.Length);
 			this.sendBuffer.ReadFrom(stream);
 
 			if(!this.isSending)

+ 13 - 16
Unity/Assets/Scripts/Module/Message/Session.cs

@@ -24,7 +24,7 @@ namespace ETModel
 		private AChannel channel;
 
 		private readonly Dictionary<int, Action<IResponse>> requestCallback = new Dictionary<int, Action<IResponse>>();
-		private readonly List<byte[]> byteses = new List<byte[]>() { new byte[1], new byte[0] };
+		private readonly List<byte[]> byteses = new List<byte[]>() { new byte[2], new byte[1], new byte[2] };
 
 		public NetworkComponent Network
 		{
@@ -124,6 +124,10 @@ namespace ETModel
 
 		private void Run(Packet packet)
 		{
+			packet.Flag = packet.Bytes[Packet.FlagIndex];
+			packet.Opcode = BitConverter.ToUInt16(packet.Bytes, Packet.OpcodeIndex);
+			packet.Stream.Seek(Packet.MessageIndex, SeekOrigin.Begin);
+			
 			byte flag = packet.Flag;
 			ushort opcode = packet.Opcode;
 			
@@ -259,19 +263,19 @@ namespace ETModel
 			{
 				throw new Exception("session已经被Dispose了");
 			}
-			this.byteses[0][0] = flag;
-			this.byteses[1] = BitConverter.GetBytes(opcode);
 
 			MemoryStream stream = this.Stream;
 			
-			int index = Packet.Index;
-			stream.Seek(index, SeekOrigin.Begin);
-			stream.SetLength(index);
-			var  bb = this.Network.MessagePacker.SerializeTo(message);
+			stream.Seek(Packet.MessageIndex, SeekOrigin.Begin);
+			stream.SetLength(Packet.MessageIndex);
 			this.Network.MessagePacker.SerializeTo(message, stream);
-			
 			stream.Seek(0, SeekOrigin.Begin);
-			index = 0;
+			
+			ushort size = (ushort)(stream.Length - Packet.SizeLength);
+			this.byteses[0].WriteTo(0, size);
+			this.byteses[1][0] = flag;
+			this.byteses[2].WriteTo(0, opcode);
+			int index = 0;
 			foreach (var bytes in this.byteses)
 			{
 				Array.Copy(bytes, 0, stream.GetBuffer(), index, bytes.Length);
@@ -283,14 +287,7 @@ namespace ETModel
 			if (this.Network.AppType == AppType.AllServer)
 			{
 				Session session = this.Network.Entity.GetComponent<NetInnerComponent>().Get(this.RemoteAddress);
-
 				Packet packet = ((TChannel)this.channel).parser.packet;
-
-				packet.Flag = flag;
-				packet.Opcode = opcode;
-				packet.Stream.Seek(0, SeekOrigin.Begin);
-				packet.Stream.SetLength(0);
-				this.Network.MessagePacker.SerializeTo(message, stream);
 				session.Run(packet);
 				return;
 			}