Răsfoiți Sursa

抽出IService和IChannel接口,用TCP实现TService TChannel, UDP实现UService UChannel,可以非常方便切换TCP和UDP协议

tanghai 11 ani în urmă
părinte
comite
8ce25cc17b

+ 30 - 0
CSharp/CSharp.sln

@@ -50,6 +50,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ENet", "Platform\ENet\ENet.
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UNetTest", "Platform\UNetTest\UNetTest.csproj", "{901A8E5C-C4C6-4C3C-8E18-068D75119F5D}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UNetExe", "Platform\UNetExe\UNetExe.csproj", "{CBA52DC8-1C80-4A79-9AC5-73514EBBD749}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Network", "Platform\Network\Network.csproj", "{3BD499FF-3C34-4920-8B21-C55FBA580843}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -222,6 +226,30 @@ Global
 		{901A8E5C-C4C6-4C3C-8E18-068D75119F5D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
 		{901A8E5C-C4C6-4C3C-8E18-068D75119F5D}.Release|Win32.ActiveCfg = Release|Any CPU
 		{901A8E5C-C4C6-4C3C-8E18-068D75119F5D}.Release|x86.ActiveCfg = Release|Any CPU
+		{CBA52DC8-1C80-4A79-9AC5-73514EBBD749}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CBA52DC8-1C80-4A79-9AC5-73514EBBD749}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CBA52DC8-1C80-4A79-9AC5-73514EBBD749}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{CBA52DC8-1C80-4A79-9AC5-73514EBBD749}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{CBA52DC8-1C80-4A79-9AC5-73514EBBD749}.Debug|Win32.ActiveCfg = Debug|Any CPU
+		{CBA52DC8-1C80-4A79-9AC5-73514EBBD749}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{CBA52DC8-1C80-4A79-9AC5-73514EBBD749}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CBA52DC8-1C80-4A79-9AC5-73514EBBD749}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CBA52DC8-1C80-4A79-9AC5-73514EBBD749}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{CBA52DC8-1C80-4A79-9AC5-73514EBBD749}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{CBA52DC8-1C80-4A79-9AC5-73514EBBD749}.Release|Win32.ActiveCfg = Release|Any CPU
+		{CBA52DC8-1C80-4A79-9AC5-73514EBBD749}.Release|x86.ActiveCfg = Release|Any CPU
+		{3BD499FF-3C34-4920-8B21-C55FBA580843}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3BD499FF-3C34-4920-8B21-C55FBA580843}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3BD499FF-3C34-4920-8B21-C55FBA580843}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{3BD499FF-3C34-4920-8B21-C55FBA580843}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{3BD499FF-3C34-4920-8B21-C55FBA580843}.Debug|Win32.ActiveCfg = Debug|Any CPU
+		{3BD499FF-3C34-4920-8B21-C55FBA580843}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{3BD499FF-3C34-4920-8B21-C55FBA580843}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3BD499FF-3C34-4920-8B21-C55FBA580843}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3BD499FF-3C34-4920-8B21-C55FBA580843}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{3BD499FF-3C34-4920-8B21-C55FBA580843}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{3BD499FF-3C34-4920-8B21-C55FBA580843}.Release|Win32.ActiveCfg = Release|Any CPU
+		{3BD499FF-3C34-4920-8B21-C55FBA580843}.Release|x86.ActiveCfg = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -241,5 +269,7 @@ Global
 		{D0B4CFAC-A368-4742-9863-68776CFA9938} = {ADBF5F67-B480-4A93-9D50-C81856FC61A9}
 		{C9992B7C-313E-4C9F-A954-640D01EDFB58} = {ADBF5F67-B480-4A93-9D50-C81856FC61A9}
 		{901A8E5C-C4C6-4C3C-8E18-068D75119F5D} = {ADBF5F67-B480-4A93-9D50-C81856FC61A9}
+		{CBA52DC8-1C80-4A79-9AC5-73514EBBD749} = {ADBF5F67-B480-4A93-9D50-C81856FC61A9}
+		{3BD499FF-3C34-4920-8B21-C55FBA580843} = {ADBF5F67-B480-4A93-9D50-C81856FC61A9}
 	EndGlobalSection
 EndGlobal

+ 31 - 0
CSharp/Platform/Network/IChannel.cs

@@ -0,0 +1,31 @@
+using System;
+using System.Threading.Tasks;
+
+namespace Network
+{
+	[Flags]
+	public enum PacketFlags
+	{
+		None = 0,
+		Reliable = 1 << 0,
+		Unsequenced = 1 << 1,
+		NoAllocate = 1 << 2
+	}
+
+	public interface IChannel: IDisposable
+	{
+		/// <summary>
+		/// 发送消息
+		/// </summary>
+		void SendAsync(byte[] buffer, byte channelID = 0, PacketFlags flags = PacketFlags.Reliable);
+
+		/// <summary>
+		/// 接收消息
+		/// </summary>
+		Task<byte[]> RecvAsync();
+
+		Task<bool> DisconnnectAsync();
+
+		string RemoteAddress { get; }
+	}
+}

+ 24 - 0
CSharp/Platform/Network/IService.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Threading.Tasks;
+
+namespace Network
+{
+	public interface IService: IDisposable
+	{
+		/// <summary>
+		/// 将函数调用加入IService线程
+		/// </summary>
+		/// <param name="action"></param>
+		void Add(Action action);
+
+		Task<IChannel> GetChannel(string host, int port);
+
+		Task<IChannel> GetChannel(string address);
+
+		Task<IChannel> GetChannel();
+
+		void Remove(IChannel channel);
+
+		void Start();
+	}
+}

+ 54 - 0
CSharp/Platform/Network/Network.csproj

@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{3BD499FF-3C34-4920-8B21-C55FBA580843}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Network</RootNamespace>
+    <AssemblyName>Network</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="IService.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="IChannel.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 36 - 0
CSharp/Platform/Network/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的常规信息通过以下
+// 特性集控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("Network")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("Network")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 使此程序集中的类型
+// 对 COM 组件不可见。  如果需要从 COM 访问此程序集中的类型,
+// 则将该类型上的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("16f6d5fb-6535-4e2b-afb5-e9a1b240c584")]
+
+// 程序集的版本信息由下面四个值组成: 
+//
+//      主版本
+//      次版本 
+//      生成号
+//      修订号
+//
+// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
+// 方法是按如下所示使用“*”: 
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 0 - 1
CSharp/Platform/TNet/IPoller.cs

@@ -1,5 +1,4 @@
 using System;
-using MongoDB.Bson;
 
 namespace TNet
 {

+ 76 - 0
CSharp/Platform/TNet/PacketParser.cs

@@ -0,0 +1,76 @@
+using System;
+
+namespace TNet
+{
+	internal enum ParserState
+	{
+		PacketSize,
+		PacketBody,
+	}
+
+	internal class PacketParser
+	{
+		private readonly TBuffer buffer;
+
+		private int packetSize;
+		private readonly byte[] packetSizeBuffer = new byte[4];
+		private ParserState state;
+		private byte[] packet;
+		private bool isOK;
+
+		public PacketParser(TBuffer buffer)
+		{
+			this.buffer = buffer;
+		}
+
+		public bool Parse()
+		{
+			if (this.isOK)
+			{
+				return true;
+			}
+
+			bool finish = false;
+			while (!finish)
+			{
+				switch (state)
+				{
+					case ParserState.PacketSize:
+						if (buffer.Count < 4)
+						{
+							finish = true;
+						}
+						else
+						{
+							buffer.RecvFrom(packetSizeBuffer);
+							packetSize = BitConverter.ToInt32(packetSizeBuffer, 0);
+							state = ParserState.PacketBody;
+						}
+						break;
+					case ParserState.PacketBody:
+						if (buffer.Count < packetSize)
+						{
+							finish = true;
+						}
+						else
+						{
+							this.packet = new byte[packetSize];
+							buffer.RecvFrom(this.packet);
+							this.isOK = true;
+							state = ParserState.PacketSize;
+							finish = true;
+						}
+						break;
+				}
+			}
+			return this.isOK;
+		}
+
+		public byte[] GetPacket()
+		{
+			byte[] result = packet;
+			this.isOK = false;
+			return result;
+		}
+	}
+}

+ 1 - 1
CSharp/Platform/TNet/TBuffer.cs

@@ -3,7 +3,7 @@ using System.Collections.Generic;
 
 namespace TNet
 {
-	public class TBuffer
+	internal class TBuffer
 	{
 		public const int ChunkSize = 8096;
 

+ 59 - 52
CSharp/Platform/TNet/TSession.cs → CSharp/Platform/TNet/TChannel.cs

@@ -1,68 +1,59 @@
 using System;
+using System.Threading.Tasks;
 using Common.Helper;
 using Common.Logger;
 using MongoDB.Bson;
+using Network;
 
 namespace TNet
 {
-	public class TSession: IDisposable
+	internal class TChannel: IChannel
 	{
-		private const int RecvSendInterval = 100;
-		private readonly TServer server;
+		private const int SendInterval = 50;
+
+		private readonly TService service;
 		private TSocket socket;
+
 		private readonly TBuffer recvBuffer = new TBuffer();
 		private readonly TBuffer sendBuffer = new TBuffer();
-		public ObjectId SendTimer = ObjectId.Empty;
-		public ObjectId RecvTimer = ObjectId.Empty;
-		private event Action onRecv = () => { };
-		private event Action onSend = () => { };
 
-		public event Action OnRecv
-		{
-			add
-			{
-				this.onRecv += value;
-			}
-			remove
-			{
-				this.onRecv -= value;
-			} 
-		}
-		public event Action OnSend
-		{
-			add
-			{
-				this.onSend += value;
-			}
-			remove
-			{
-				this.onSend -= value;
-			}
-		}
+		private ObjectId sendTimer = ObjectId.Empty;
+		private Action onParseComplete = () => { };
+		private readonly PacketParser parser;
 
-		public TSession(TSocket socket, TServer server)
+		public TChannel(TSocket socket, TService service)
 		{
 			this.socket = socket;
-			this.server = server;
+			this.service = service;
+			this.parser = new PacketParser(recvBuffer);
+			Start();
 		}
 
 		public void Dispose()
 		{
-			if (this.socket == null)
+			if (socket == null)
 			{
 				return;
 			}
-			this.server.Remove(socket.RemoteAddress);
-			this.socket.Dispose();
+			this.service.Remove(this);
+			socket.Dispose();
 			this.socket = null;
 		}
 
-		public void Send(byte[] buffer)
+		public void SendAsync(byte[] buffer, byte channelID = 0, PacketFlags flags = PacketFlags.Reliable)
 		{
 			this.sendBuffer.SendTo(buffer);
-			if (this.SendTimer == ObjectId.Empty)
+			if (this.sendTimer == ObjectId.Empty)
 			{
-				this.SendTimer = this.server.Timer.Add(TimeHelper.Now() + RecvSendInterval, this.SendTimerCallback);
+				this.sendTimer = this.service.Timer.Add(TimeHelper.Now() + SendInterval, this.SendTimerCallback);
+			}
+		}
+
+		public ObjectId SendTimer
+		{
+			get
+			{
+				return this.sendTimer;
 			}
 		}
 
@@ -96,24 +87,45 @@ namespace TNet
 				Log.Trace(e.ToString());
 			}
 
-			this.onSend();
-			this.SendTimer = ObjectId.Empty;
+			this.sendTimer = ObjectId.Empty;
+		}
+
+		public Task<byte[]> RecvAsync()
+		{
+			var tcs = new TaskCompletionSource<byte[]>();
+
+			if (parser.Parse())
+			{
+				tcs.SetResult(parser.GetPacket());
+			}
+			else
+			{
+				this.onParseComplete = () => this.ParseComplete(tcs);	
+			}
+			return tcs.Task;
+		}
+
+		public async Task<bool> DisconnnectAsync()
+		{
+			return await this.socket.DisconnectAsync();
 		}
 
-		public int RecvSize
+		public string RemoteAddress
 		{
 			get
 			{
-				return this.recvBuffer.Count;
+				return this.socket.RemoteAddress;
 			}
 		}
 
-		public void Recv(byte[] buffer)
+		private void ParseComplete(TaskCompletionSource<byte[]> tcs)
 		{
-			this.recvBuffer.RecvFrom(buffer);
+			byte[] packet = parser.GetPacket();
+			this.onParseComplete = () => { };
+			tcs.SetResult(packet);
 		}
 
-		public async void Start()
+		private async void Start()
 		{
 			try
 			{
@@ -133,9 +145,10 @@ namespace TNet
 						this.recvBuffer.LastIndex = 0;
 					}
 
-					if (this.RecvTimer == ObjectId.Empty)
+					// 解析封包
+					if (parser.Parse())
 					{
-						this.RecvTimer = this.server.Timer.Add(TimeHelper.Now() + RecvSendInterval, this.RecvTimerCallback);
+						this.onParseComplete();
 					}
 				}
 			}
@@ -144,11 +157,5 @@ namespace TNet
 				Log.Trace(e.ToString());
 			}
 		}
-
-		private void RecvTimerCallback()
-		{
-			this.onRecv();
-			this.RecvTimer = ObjectId.Empty;
-		}
 	}
 }

+ 7 - 2
CSharp/Platform/TNet/TNet.csproj

@@ -51,11 +51,12 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="IPoller.cs" />
+    <Compile Include="PacketParser.cs" />
     <Compile Include="TPoller.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="TBuffer.cs" />
-    <Compile Include="TServer.cs" />
-    <Compile Include="TSession.cs" />
+    <Compile Include="TService.cs" />
+    <Compile Include="TChannel.cs" />
     <Compile Include="TSocket.cs" />
   </ItemGroup>
   <ItemGroup>
@@ -63,6 +64,10 @@
       <Project>{19f8f043-1f99-4550-99df-dea5c7d77e55}</Project>
       <Name>Common</Name>
     </ProjectReference>
+    <ProjectReference Include="..\Network\Network.csproj">
+      <Project>{3bd499ff-3c34-4920-8b21-c55fba580843}</Project>
+      <Name>Network</Name>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />

+ 1 - 3
CSharp/Platform/TNet/TPoller.cs

@@ -1,12 +1,10 @@
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
-using Common.Base;
-using MongoDB.Bson;
 
 namespace TNet
 {
-	public class TPoller : IPoller
+	internal class TPoller : IPoller
 	{
 		// 线程同步队列,发送接收socket回调都放到该队列,由poll线程统一执行
 		private readonly BlockingCollection<Action> blockingCollection = new BlockingCollection<Action>();

+ 0 - 113
CSharp/Platform/TNet/TServer.cs

@@ -1,113 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Common.Base;
-using MongoDB.Bson;
-
-namespace TNet
-{
-	public class TServer: IDisposable
-	{
-		private IPoller poller = new TPoller();
-		private TSocket acceptor;
-
-		private readonly Dictionary<string, TSession> sessions = new Dictionary<string, TSession>();
-
-		private readonly TimerManager timerManager = new TimerManager();
-		
-		public TServer(int port)
-		{
-			this.acceptor = new TSocket(poller);
-			this.acceptor.Bind("127.0.0.1", port);
-			this.acceptor.Listen(100);
-		}
-
-		public void Dispose()
-		{
-			if (this.poller == null)
-			{
-				return;
-			}
-			
-			this.acceptor.Dispose();
-			this.acceptor = null;
-			this.poller = null;
-		}
-
-		public void Remove(string address)
-		{
-			TSession session;
-			if (!this.sessions.TryGetValue(address, out session))
-			{
-				return;
-			}
-			if (session.SendTimer != ObjectId.Empty)
-			{
-				this.Timer.Remove(session.SendTimer);
-			}
-
-			if (session.RecvTimer != ObjectId.Empty)
-			{
-				this.Timer.Remove(session.RecvTimer);
-			}
-			this.sessions.Remove(address);
-		}
-
-		public void Push(Action action)
-		{
-			this.poller.Add(action);
-		}
-
-		public async Task<TSession> AcceptAsync()
-		{
-			TSocket newSocket = new TSocket(poller);
-			await this.acceptor.AcceptAsync(newSocket);
-			TSession session = new TSession(newSocket, this);
-			sessions[newSocket.RemoteAddress] = session;
-			return session;
-		}
-
-		public async Task<TSession> ConnectAsync(string host, int port)
-		{
-			TSocket newSocket = new TSocket(poller);
-			await newSocket.ConnectAsync(host, port);
-			TSession session = new TSession(newSocket, this);
-			sessions[newSocket.RemoteAddress] = session;
-			return session;
-		}
-
-		public TSession Get(string host, int port)
-		{
-			TSession session = null;
-			this.sessions.TryGetValue(host + ":" + port, out session);
-			return session;
-		}
-
-		public async Task<TSession> GetOrCreate(string host, int port)
-		{
-			TSession session = null;
-			if (this.sessions.TryGetValue(host + ":" + port, out session))
-			{
-				return session;
-			}
-			return await ConnectAsync(host, port);
-		}
-
-		public void Start()
-		{
-			while (true)
-			{
-				poller.Run(1);
-				this.timerManager.Refresh();
-			}
-		}
-
-		public TimerManager Timer
-		{
-			get
-			{
-				return this.timerManager;
-			}
-		}
-	}
-}

+ 118 - 0
CSharp/Platform/TNet/TService.cs

@@ -0,0 +1,118 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Common.Base;
+using Network;
+
+namespace TNet
+{
+	public class TService: IService
+	{
+		private IPoller poller = new TPoller();
+		private TSocket acceptor;
+
+		private readonly Dictionary<string, TChannel> channels = new Dictionary<string, TChannel>();
+
+		private readonly TimerManager timerManager = new TimerManager();
+
+		public TService(string host, int port)
+		{
+			this.acceptor = new TSocket(poller);
+			this.acceptor.Bind(host, port);
+			this.acceptor.Listen(100);
+		}
+
+		public void Dispose()
+		{
+			if (this.poller == null)
+			{
+				return;
+			}
+			
+			this.acceptor.Dispose();
+			this.acceptor = null;
+			this.poller = null;
+		}
+
+		public void Add(Action action)
+		{
+			this.poller.Add(action);
+		}
+
+		private async void AcceptAsync()
+		{
+			while (true)
+			{
+				TSocket newSocket = new TSocket(poller);
+				await this.acceptor.AcceptAsync(newSocket);
+				TChannel channel = new TChannel(newSocket, this);
+				channels[newSocket.RemoteAddress] = channel;
+			}
+		}
+
+		private async Task<IChannel> ConnectAsync(string host, int port)
+		{
+			TSocket newSocket = new TSocket(poller);
+			await newSocket.ConnectAsync(host, port);
+			TChannel channel = new TChannel(newSocket, this);
+			channels[newSocket.RemoteAddress] = channel;
+			return channel;
+		}
+
+		public async Task<IChannel> GetChannel()
+		{
+			TSocket socket = new TSocket(this.poller);
+			await acceptor.AcceptAsync(socket);
+			TChannel channel = new TChannel(socket, this);
+			channels[channel.RemoteAddress] = channel;
+			return channel;
+		}
+
+		public void Remove(IChannel channel)
+		{
+			TChannel tChannel = channel as TChannel;
+			if (tChannel == null)
+			{
+				return;
+			}
+			this.channels.Remove(channel.RemoteAddress);
+			this.timerManager.Remove(tChannel.SendTimer);
+		}
+
+		public async Task<IChannel> GetChannel(string host, int port)
+		{
+			TChannel channel = null;
+			if (this.channels.TryGetValue(host + ":" + port, out channel))
+			{
+				return channel;
+			}
+			return await ConnectAsync(host, port);
+		}
+
+		public async Task<IChannel> GetChannel(string address)
+		{
+			string[] ss = address.Split(':');
+			int port = Convert.ToInt32(ss[1]);
+			return await GetChannel(ss[0], port);
+		}
+
+		public void Start()
+		{
+			AcceptAsync();
+
+			while (true)
+			{
+				poller.Run(1);
+				this.timerManager.Refresh();
+			}
+		}
+
+		internal TimerManager Timer
+		{
+			get
+			{
+				return this.timerManager;
+			}
+		}
+	}
+}

+ 0 - 2
CSharp/Platform/TNetTest/TNetTest.csproj

@@ -52,8 +52,6 @@
   </Choose>
   <ItemGroup>
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="TServerTest.cs" />
-    <Compile Include="TSocketTest.cs" />
     <Compile Include="TcpListenerTest.cs" />
   </ItemGroup>
   <ItemGroup>

+ 0 - 89
CSharp/Platform/TNetTest/TServerTest.cs

@@ -1,89 +0,0 @@
-using System.Threading;
-using System.Threading.Tasks;
-using Common.Helper;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using TNet;
-
-namespace TNetTest
-{
-	[TestClass]
-	public class TServerTest
-	{
-		private Barrier barrier;
-		private const int clientNum = 10;
-
-		private const int sendNum = 10000000;
-
-		[TestMethod]
-		public void SendRecv()
-		{
-			barrier = new Barrier(clientNum + 1);
-			TServer server = new TServer(10000);
-			Task.Factory.StartNew(() => server.Start(), TaskCreationOptions.LongRunning);
-
-			server.Push(() => Server(server));
-			Thread.Sleep(1000);
-
-			for (int i = 0; i < clientNum; ++i)
-			{
-				server.Push(() => this.ClientRequest(server));
-			}
-
-			this.barrier.SignalAndWait();
-		}
-
-		private async void Server(TServer server)
-		{
-			for (int i = 0; i < clientNum; i++)
-			{
-				TSession session = await server.AcceptAsync();
-				int count = 0;
-				session.OnRecv += () => this.ServerResponse(session, ref count);
-				session.Start();
-			}
-		}
-
-		private void ServerResponse(TSession session, ref int count)
-		{
-			byte[] buffer = new byte[10];
-			while (session.RecvSize >= 10)
-			{
-				buffer = new byte[10];
-				session.Recv(buffer);
-				Assert.AreEqual("0123456789", buffer.ToStr());
-				++count;
-			}
-
-			if (count == sendNum)
-			{
-				buffer = "9876543210".ToByteArray();
-				session.Send(buffer);
-			}
-		}
-
-		private async void ClientRequest(TServer server)
-		{
-			TSession session = await server.ConnectAsync("127.0.0.1", 10000);
-			session.OnRecv += () => ClientOnResponse(session);
-			session.Start();
-
-			byte[] buffer = "0123456789".ToByteArray();
-			for (int i = 0; i < sendNum; i++)
-			{
-				session.Send(buffer);
-			}
-		}
-
-		private void ClientOnResponse(TSession session)
-		{
-			if (session.RecvSize < 10)
-			{
-				return;
-			}
-			byte[] buffer = new byte[10];
-			session.Recv(buffer);
-			Assert.AreEqual("9876543210", buffer.ToStr());
-			this.barrier.RemoveParticipant();
-		}
-	}
-}

+ 0 - 85
CSharp/Platform/TNetTest/TSocketTest.cs

@@ -1,85 +0,0 @@
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using Common.Helper;
-using Common.Logger;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using TNet;
-
-namespace TNetTest
-{
-	[TestClass]
-	public class TSocketTest
-	{
-		private Barrier barrier;
-		private const int clientNum = 10;
-
-		[TestMethod]
-		public void SendRecv()
-		{
-			barrier = new Barrier(clientNum + 2);
-			IPoller poller = new TPoller();
-			Task.Factory.StartNew(() =>
-			{
-				while (true)
-				{
-					poller.Run(1);
-				}
-			}, 
-			
-			TaskCreationOptions.LongRunning);
-
-			poller.Add(() => Server(poller));
-			Thread.Sleep(500);
-
-			for (int i = 0; i < clientNum; ++i)
-			{
-				poller.Add(() => Request(poller));
-			}
-
-			this.barrier.SignalAndWait();
-		}
-
-		private async void Server(IPoller poller)
-		{
-			TSocket acceptor = new TSocket(poller);
-			acceptor.Bind("127.0.0.1", 10000);
-			acceptor.Listen(100);
-
-			for (int i = 0; i < clientNum; i++)
-			{
-				TSocket socket = new TSocket(poller);
-				await acceptor.AcceptAsync(socket);
-				Response(socket);
-			}
-			this.barrier.RemoveParticipant();
-		}
-
-		private static async void Response(TSocket socket)
-		{
-			byte[] buffer = new byte[10];
-			for (int i = 0; i < 10000; i++)
-			{
-				await socket.RecvAsync(buffer, 0, buffer.Length);
-				Array.Reverse(buffer);
-				await socket.SendAsync(buffer, 0, buffer.Length);
-			}
-			await socket.DisconnectAsync();
-		}
-
-		private async void Request(IPoller poller)
-		{
-			TSocket client = new TSocket(poller);
-			for (int i = 0; i < 10000; i++)
-			{
-				await client.ConnectAsync("127.0.0.1", 10000);
-				byte[] buffer = "0123456789".ToByteArray();
-				await client.SendAsync(buffer, 0, buffer.Length);
-				await client.RecvAsync(buffer, 0, buffer.Length);
-				Assert.AreEqual("9876543210", buffer.ToStr());
-			}
-			Log.Debug("1111111111111111111111111111111111111");
-			this.barrier.RemoveParticipant();
-		}
-	}
-}

+ 2 - 1
CSharp/Platform/UNet/EPacket.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Runtime.InteropServices;
+using Network;
 
 namespace UNet
 {
@@ -87,7 +88,7 @@ namespace UNet
 		{
 			get
 			{
-				var enetPacket = this.Struct;
+				ENetPacket enetPacket = this.Struct;
 				var bytes = new byte[enetPacket.DataLength];
 				Marshal.Copy(enetPacket.Data, bytes, 0, (int) enetPacket.DataLength);
 				return bytes;

+ 20 - 44
CSharp/Platform/UNet/EService.cs

@@ -34,24 +34,12 @@ namespace UNet
 		private readonly object eventsLock = new object();
 		private Action events;
 
-		public EService(
-				string hostName, ushort port, uint peerLimit = NativeMethods.ENET_PROTOCOL_MAXIMUM_PEER_ID,
-				uint channelLimit = 0, uint incomingBandwidth = 0, uint outgoingBandwidth = 0)
+		public EService(string hostName, ushort port)
 		{
-			if (peerLimit > NativeMethods.ENET_PROTOCOL_MAXIMUM_PEER_ID)
-			{
-				throw new ArgumentOutOfRangeException(string.Format("peerLimit: {0}", peerLimit));
-			}
-
-			if (channelLimit > NativeMethods.ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
-			{
-				throw new ArgumentOutOfRangeException(string.Format("channelLimit: {0}", channelLimit));
-			}
-
 			var address = new Address { HostName = hostName, Port = port };
 			ENetAddress nativeAddress = address.Struct;
-			this.host = NativeMethods.EnetHostCreate(ref nativeAddress, peerLimit, channelLimit,
-					incomingBandwidth, outgoingBandwidth);
+			this.host = NativeMethods.EnetHostCreate(
+				ref nativeAddress, NativeMethods.ENET_PROTOCOL_MAXIMUM_PEER_ID, 0, 0, 0);
 
 			if (this.host == IntPtr.Zero)
 			{
@@ -59,22 +47,10 @@ namespace UNet
 			}
 		}
 
-		public EService(
-				uint peerLimit = NativeMethods.ENET_PROTOCOL_MAXIMUM_PEER_ID, uint channelLimit = 0,
-				uint incomingBandwidth = 0, uint outgoingBandwidth = 0)
+		public EService()
 		{
-			if (peerLimit > NativeMethods.ENET_PROTOCOL_MAXIMUM_PEER_ID)
-			{
-				throw new ArgumentOutOfRangeException(string.Format("peerLimit: {0}", peerLimit));
-			}
-
-			if (channelLimit > NativeMethods.ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
-			{
-				throw new ArgumentOutOfRangeException(string.Format("channelLimit: {0}", channelLimit));
-			}
-
-			this.host = NativeMethods.EnetHostCreate(IntPtr.Zero, peerLimit, channelLimit, incomingBandwidth,
-					outgoingBandwidth);
+			this.host = NativeMethods.EnetHostCreate(
+				IntPtr.Zero, NativeMethods.ENET_PROTOCOL_MAXIMUM_PEER_ID, 0, 0, 0);
 
 			if (this.host == IntPtr.Zero)
 			{
@@ -235,8 +211,8 @@ namespace UNet
 						// 这是一个connect peer
 						if (this.PeersManager.ContainsKey(eEvent.PeerPtr))
 						{
-							ESocket eSocket = this.PeersManager[eEvent.PeerPtr];
-							eSocket.OnConnected(eEvent);
+							USocket uSocket = this.PeersManager[eEvent.PeerPtr];
+							uSocket.OnConnected(eEvent);
 						}
 								// accept peer
 						else
@@ -248,16 +224,16 @@ namespace UNet
 							}
 							else
 							{
-								ESocket eSocket = this.PeersManager[IntPtr.Zero];
-								eSocket.OnConnected(eEvent);
+								USocket uSocket = this.PeersManager[IntPtr.Zero];
+								uSocket.OnConnected(eEvent);
 							}
 						}
 						break;
 					}
 					case EventType.Receive:
 					{
-						ESocket eSocket = this.PeersManager[eEvent.PeerPtr];
-						eSocket.OnReceived(eEvent);
+						USocket uSocket = this.PeersManager[eEvent.PeerPtr];
+						uSocket.OnReceived(eEvent);
 						break;
 					}
 					case EventType.Disconnect:
@@ -275,24 +251,24 @@ namespace UNet
 
 						// 链接已经被应用层接收
 						eEvent.EventState = EventState.DISCONNECTED;
-						ESocket eSocket = this.PeersManager[eEvent.PeerPtr];
+						USocket uSocket = this.PeersManager[eEvent.PeerPtr];
 						this.PeersManager.Remove(eEvent.PeerPtr);
 
 						// 等待的task将抛出异常
-						if (eSocket.Connected != null)
+						if (uSocket.Connected != null)
 						{
-							eSocket.OnConnected(eEvent);
+							uSocket.OnConnected(eEvent);
 						}
-						else if (eSocket.Received != null)
+						else if (uSocket.Received != null)
 						{
-							eSocket.OnReceived(eEvent);
+							uSocket.OnReceived(eEvent);
 						}
-						else if (eSocket.Disconnect != null)
+						else if (uSocket.Disconnect != null)
 						{
-							eSocket.OnDisconnect(eEvent);
+							uSocket.OnDisconnect(eEvent);
 						}
 
-						eSocket.OnError(ErrorCode.ClientDisconnect);
+						uSocket.OnError(ErrorCode.ClientDisconnect);
 						break;
 					}
 				}

+ 1 - 0
CSharp/Platform/UNet/NativeMethods.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Runtime.InteropServices;
 using System.Text;
+using Network;
 
 namespace UNet
 {

+ 1 - 10
CSharp/Platform/UNet/NativeStructs.cs

@@ -25,16 +25,7 @@ namespace UNet
 		AcknowledgingDisconnect = 8,
 		Zombie = 9
 	}
-
-	[Flags]
-	public enum PacketFlags
-	{
-		None = 0,
-		Reliable = 1 << 0,
-		Unsequenced = 1 << 1,
-		NoAllocate = 1 << 2
-	}
-
+	
 	[StructLayout(LayoutKind.Sequential)]
 	public struct ENetAddress
 	{

+ 4 - 4
CSharp/Platform/UNet/PeersManager.cs

@@ -5,11 +5,11 @@ namespace UNet
 {
 	internal class PeersManager
 	{
-		private readonly Dictionary<IntPtr, ESocket> peersManager = new Dictionary<IntPtr, ESocket>();
+		private readonly Dictionary<IntPtr, USocket> peersManager = new Dictionary<IntPtr, USocket>();
 
-		public void Add(IntPtr peerPtr, ESocket eSocket)
+		public void Add(IntPtr peerPtr, USocket uSocket)
 		{
-			this.peersManager.Add(peerPtr, eSocket);
+			this.peersManager.Add(peerPtr, uSocket);
 		}
 
 		public void Remove(IntPtr peerPtr)
@@ -26,7 +26,7 @@ namespace UNet
 			return false;
 		}
 
-		public ESocket this[IntPtr peerPtr]
+		public USocket this[IntPtr peerPtr]
 		{
 			get
 			{

+ 53 - 0
CSharp/Platform/UNet/UChannel.cs

@@ -0,0 +1,53 @@
+using System.Threading.Tasks;
+using Network;
+
+namespace UNet
+{
+	internal class UChannel: IChannel
+	{
+		private readonly UService service;
+		private USocket socket;
+
+
+		public UChannel(USocket socket, UService service)
+		{
+			this.socket = socket;
+			this.service = service;
+		}
+
+		public void Dispose()
+		{
+			if (socket == null)
+			{
+				return;
+			}
+			service.Remove(this);
+			socket.Dispose();
+			this.socket = null;
+		}
+
+		public void SendAsync(byte[] buffer, byte channelID = 0, PacketFlags flags = PacketFlags.Reliable)
+		{
+			this.socket.WriteAsync(buffer, channelID, flags);
+		}
+
+
+		public async Task<byte[]> RecvAsync()
+		{
+			return await this.socket.ReadAsync();
+		}
+
+		public string RemoteAddress
+		{
+			get
+			{
+				return this.socket.RemoteAddress;
+			}
+		}
+
+		public async Task<bool> DisconnnectAsync()
+		{
+			return await this.socket.DisconnectAsync();
+		}
+	}
+}

+ 9 - 1
CSharp/Platform/UNet/UNet.csproj

@@ -48,11 +48,19 @@
     <Compile Include="PeersManager.cs" />
     <Compile Include="NativeStructs.cs" />
     <Compile Include="EPacket.cs" />
-    <Compile Include="ESocket.cs" />
+    <Compile Include="USocket.cs" />
+    <Compile Include="UChannel.cs" />
+    <Compile Include="UService.cs" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="Properties\" />
   </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Network\Network.csproj">
+      <Project>{3bd499ff-3c34-4920-8b21-c55fba580843}</Project>
+      <Name>Network</Name>
+    </ProjectReference>
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 92 - 0
CSharp/Platform/UNet/UService.cs

@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Network;
+
+namespace UNet
+{
+	public class UService: IService
+	{
+		private EService service;
+
+		private readonly Dictionary<string, UChannel> channels = new Dictionary<string, UChannel>();
+
+		public UService(string host, int port)
+		{
+			this.service = new EService(host, (ushort)port);
+		}
+
+		public void Dispose()
+		{
+			if (service == null)
+			{
+				return;
+			}
+			service.Dispose();
+			service = null;
+		}
+
+		public void Add(Action action)
+		{
+			this.service.Events += action;
+		}
+
+		public EService Service
+		{
+			get
+			{
+				return service;
+			}
+		}
+
+		private async Task<IChannel> ConnectAsync(string host, int port)
+		{
+			USocket newSocket = new USocket(service);
+			await newSocket.ConnectAsync(host, (ushort) port);
+			UChannel channel = new UChannel(newSocket, this);
+			channels[channel.RemoteAddress] = channel;
+			return channel;
+		}
+
+		public async Task<IChannel> GetChannel(string address)
+		{
+			string[] ss = address.Split(':');
+			int port = Convert.ToInt32(ss[1]);
+			return await GetChannel(ss[0], port);
+		}
+
+		public async Task<IChannel> GetChannel()
+		{
+			USocket socket = new USocket(this.service);
+			await socket.AcceptAsync();
+			UChannel channel = new UChannel(socket, this);
+			channels[channel.RemoteAddress] = channel;
+			return channel;
+		}
+
+		public void Remove(IChannel channel)
+		{
+			UChannel tChannel = channel as UChannel;
+			if (tChannel == null)
+			{
+				return;
+			}
+			this.channels.Remove(channel.RemoteAddress);
+		}
+
+		public async Task<IChannel> GetChannel(string host, int port)
+		{
+			UChannel channel = null;
+			if (this.channels.TryGetValue(host + ":" + port, out channel))
+			{
+				return channel;
+			}
+			return await ConnectAsync(host, port);
+		}
+
+		public void Start()
+		{
+			this.service.Start();
+		}
+	}
+}

+ 13 - 3
CSharp/Platform/UNet/ESocket.cs → CSharp/Platform/UNet/USocket.cs

@@ -2,10 +2,11 @@
 using System.Collections.Generic;
 using System.Runtime.InteropServices;
 using System.Threading.Tasks;
+using Network;
 
 namespace UNet
 {
-	public sealed class ESocket: IDisposable
+	public sealed class USocket: IDisposable
 	{
 		private IntPtr peerPtr = IntPtr.Zero;
 		private readonly EService service;
@@ -16,7 +17,7 @@ namespace UNet
 		public Action<EEvent> Disconnect { get; set; }
 		public Action<int> Error { get; set; }
 
-		public ESocket(EService service)
+		public USocket(EService service)
 		{
 			this.service = service;
 		}
@@ -42,7 +43,7 @@ namespace UNet
 				this.peerPtr = value;
 			}
 		}
-
+		
 		private ENetPeer Struct
 		{
 			get
@@ -59,6 +60,15 @@ namespace UNet
 			}
 		}
 
+		public string RemoteAddress
+		{
+			get
+			{
+				ENetPeer peer = this.Struct;
+				return peer.Address.Host + ":" + peer.Address.Port;
+			}
+		}
+
 		public PeerState State
 		{
 			get

+ 0 - 0
CSharp/Platform/ENetExe/App.config → CSharp/Platform/UNetExe/App.config


+ 2 - 2
CSharp/Platform/ENetExe/Program.cs → CSharp/Platform/UNetExe/Program.cs

@@ -1,4 +1,4 @@
-using ENetTest;
+using UNetTest;
 
 namespace ENetExe
 {
@@ -6,7 +6,7 @@ namespace ENetExe
 	{
 		private static void Main(string[] args)
 		{
-			var test = new ENetClientServerTest();
+			var test = new UNetClientServerTest();
 			test.ClientSendToServer();
 		}
 	}

+ 0 - 0
CSharp/Platform/ENetExe/Properties/AssemblyInfo.cs → CSharp/Platform/UNetExe/Properties/AssemblyInfo.cs


+ 2 - 2
CSharp/Platform/ENetExe/ENetExe.csproj → CSharp/Platform/UNetExe/UNetExe.csproj

@@ -44,9 +44,9 @@
     <None Include="App.config" />
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\ENetTest\ENetTest.csproj">
+    <ProjectReference Include="..\UNetTest\UNetTest.csproj">
       <Project>{901a8e5c-c4c6-4c3c-8e18-068d75119f5d}</Project>
-      <Name>ENetTest</Name>
+      <Name>UNetTest</Name>
     </ProjectReference>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

+ 27 - 59
CSharp/Platform/UNetTest/UNetClientServerTest.cs

@@ -1,94 +1,62 @@
-using System.Diagnostics;
+using System;
 using System.Threading;
+using System.Threading.Tasks;
 using Common.Helper;
-using Common.Logger;
 using UNet;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Network;
 
 namespace UNetTest
 {
 	[TestClass]
 	public class UNetClientServerTest
 	{
-		private const int pingPangCount = 10000;
+		private readonly Barrier barrier = new Barrier(3);
 
-		private static async void ClientEvent(EService service, string hostName, ushort port)
+		private async void ClientEvent(IService service, string hostName, ushort port)
 		{
-			var eSocket = new ESocket(service);
-			await eSocket.ConnectAsync(hostName, port);
-			var stopWatch = new Stopwatch();
-			stopWatch.Start();
-			for (int i = 0; i < pingPangCount; ++i)
-			{
-				eSocket.WriteAsync("0123456789".ToByteArray());
+			IChannel channel = await service.GetChannel(hostName, port);
+			channel.SendAsync("0123456789".ToByteArray());
 
-				var bytes = await eSocket.ReadAsync();
+			byte[] bytes = await channel.RecvAsync();
+			Assert.AreEqual("9876543210".ToByteArray(), bytes);
 
-				CollectionAssert.AreEqual("9876543210".ToByteArray(), bytes);
-			}
-			stopWatch.Stop();
-			Log.Debug("time: {0}", stopWatch.ElapsedMilliseconds);
-			await eSocket.DisconnectAsync();
-			service.Stop();
+			barrier.RemoveParticipant();
 		}
 
-		private static async void ServerEvent(EService service, Barrier barrier)
+		private async void ServerEvent(IService service)
 		{
-			barrier.SignalAndWait();
+			IChannel channel = await service.GetChannel();
+			byte[] bytes = await channel.RecvAsync();
+			Assert.AreEqual("0123456789".ToByteArray(), bytes);
+			Array.Reverse(bytes);
+			channel.SendAsync(bytes);
 
-			bool isRunning = true;
-			while (isRunning)
-			{
-				Log.Debug("start accept");
-				var eSocket = new ESocket(service);
-				await eSocket.AcceptAsync();
-				eSocket.Disconnect += ev =>
-				{
-					isRunning = false;
-					service.Stop();
-				};
-				Echo(eSocket);
-			}
-		}
-
-		private static async void Echo(ESocket eSocket)
-		{
-			for (int i = 0; i < pingPangCount; ++i)
-			{
-				var bytes = await eSocket.ReadAsync();
-
-				CollectionAssert.AreEqual("0123456789".ToByteArray(), bytes);
-
-				eSocket.WriteAsync("9876543210".ToByteArray());
-			}
+			barrier.RemoveParticipant();
 		}
 
 		[TestMethod]
 		public void ClientSendToServer()
 		{
 			const string hostName = "127.0.0.1";
-			const ushort port = 8888;
-			var clientHost = new EService();
-			var serverHost = new EService(hostName, port);
-
-			var serverThread = new Thread(() => serverHost.Start());
-			var clientThread = new Thread(() => clientHost.Start());
+			const ushort port = 8889;
+			IService clientService = new UService(hostName, 8888);
+			IService serverService = new UService(hostName, 8889);
 
-			serverThread.Start();
-			clientThread.Start();
+			Task.Factory.StartNew(() => clientService.Start(), TaskCreationOptions.LongRunning);
+			Task.Factory.StartNew(() => serverService.Start(), TaskCreationOptions.LongRunning);
 
-			var barrier = new Barrier(2);
+			
 
 			// 往server host线程增加事件,accept
-			serverHost.Events += () => ServerEvent(serverHost, barrier);
+			serverService.Add(() => ServerEvent(serverService));
 
-			barrier.SignalAndWait();
+			Thread.Sleep(1000);
 
 			// 往client host线程增加事件,client线程连接server
-			clientHost.Events += () => ClientEvent(clientHost, hostName, port);
+			clientService.Add(() => ClientEvent(clientService, hostName, port));
 
-			serverThread.Join();
-			clientThread.Join();
+			barrier.SignalAndWait();
 		}
 	}
 }

+ 4 - 0
CSharp/Platform/UNetTest/UNetTest.csproj

@@ -61,6 +61,10 @@
       <Project>{19f8f043-1f99-4550-99df-dea5c7d77e55}</Project>
       <Name>Common</Name>
     </ProjectReference>
+    <ProjectReference Include="..\Network\Network.csproj">
+      <Project>{3bd499ff-3c34-4920-8b21-c55fba580843}</Project>
+      <Name>Network</Name>
+    </ProjectReference>
     <ProjectReference Include="..\UNet\UNet.csproj">
       <Project>{d0b4cfac-a368-4742-9863-68776cfa9938}</Project>
       <Name>UNet</Name>