Просмотр исходного кода

1.增加kcp断开消息
2.修复udp socket 断开,远程udp recv调用抛异常的问题
3.支持一个udp socket多个kcp连接

tanghai 8 лет назад
Родитель
Сommit
980d8fcf0e

+ 1 - 1
Client-Server.sln

@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 15
-VisualStudioVersion = 15.0.27004.2006
+VisualStudioVersion = 15.0.27004.2009
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unity.Plugins", "Unity\Unity.Plugins.csproj", "{D1FDB199-0FB7-099D-3771-C6A942E4E326}"
 EndProject

+ 0 - 9
Unity/Assets/Scripts/Base/Helper/ByteHelper.cs

@@ -60,15 +60,6 @@ namespace Model
 			return Encoding.UTF8.GetString(bytes, index, count);
 		}
 
-		public static void WriteTo(this byte[] bytes, int offset, int num)
-		{
-			byte[] numBytes = BitConverter.GetBytes(num);
-			for (int i = 0; i < numBytes.Length; ++i)
-			{
-				bytes[offset + i] = numBytes[i];
-			}
-		}
-		
 		public static void WriteTo(this byte[] bytes, int offset, uint num)
 		{
 			byte[] numBytes = BitConverter.GetBytes(num);

+ 20 - 3
Unity/Assets/Scripts/Base/Network/KNet/KChannel.cs

@@ -39,7 +39,7 @@ namespace Model
 			this.remoteEndPoint = remoteEndPoint;
 			this.socket = socket;
 			this.parser = new PacketParser(this.recvBuffer);
-			kcp = new Kcp(this.Conn, this.Output);
+			kcp = new Kcp(this.RemoteConn, this.Output);
 			kcp.SetMtu(512);
 			kcp.NoDelay(1, 10, 2, 1);  //fast
 			this.isConnected = true;
@@ -53,6 +53,7 @@ namespace Model
 			this.Conn = conn;
 			this.socket = socket;
 			this.parser = new PacketParser(this.recvBuffer);
+
 			this.remoteEndPoint = remoteEndPoint;
 			this.lastRecvTime = kService.TimeNow;
 			this.Connect(kService.TimeNow);
@@ -67,6 +68,11 @@ namespace Model
 
 			base.Dispose();
 
+			for (int i = 0; i < 4; i++)
+			{
+				this.DisConnect();
+			}
+
 			this.socket = null;
 		}
 
@@ -82,6 +88,7 @@ namespace Model
 				return;
 			}
 			this.isConnected = true;
+
 			this.RemoteConn = responseConn;
 			this.kcp = new Kcp(responseConn, this.Output);
 			kcp.SetMtu(512);
@@ -105,12 +112,22 @@ namespace Model
 		{
 			cacheBytes.WriteTo(0, KcpProtocalType.SYN);
 			cacheBytes.WriteTo(4, this.Conn);
+			Log.Debug($"client connect: {this.Conn}");
 			this.socket.Send(cacheBytes, 8, remoteEndPoint);
 
 			// 200毫秒后再次update发送connect请求
 			this.GetService().AddToNextTimeUpdate(timeNow + 200, this.Id);
 		}
 
+		private void DisConnect()
+		{
+			cacheBytes.WriteTo(0, KcpProtocalType.FIN);
+			cacheBytes.WriteTo(4, this.Conn);
+			cacheBytes.WriteTo(8, this.RemoteConn);
+			Log.Debug($"client disconnect: {this.Conn}");
+			this.socket.Send(cacheBytes, 12, remoteEndPoint);
+		}
+
 		public void Update(uint timeNow)
 		{
 			// 如果还没连接上,发送连接请求
@@ -152,8 +169,6 @@ namespace Model
 			// 加入update队列
 			this.GetService().AddToUpdate(this.Id);
 
-			lastRecvTime = timeNow;
-
 			while (true)
 			{
 				int n = kcp.PeekSize();
@@ -171,6 +186,8 @@ namespace Model
 				// 收到的数据放入缓冲区
 				this.recvBuffer.SendTo(this.cacheBytes, 0, count);
 
+				lastRecvTime = timeNow;
+
 				if (this.recvTcs != null)
 				{
 					byte[] packet = this.parser.GetPacket();

+ 50 - 19
Unity/Assets/Scripts/Base/Network/KNet/KService.cs

@@ -10,11 +10,13 @@ namespace Model
 	{
 		public const uint SYN = 1;
 		public const uint ACK = 2;
+		public const uint FIN = 3;
 	}
 
 	public sealed class KService: AService
 	{
 		private uint IdGenerater = 1000;
+		private uint IdAccept = 2000000000;
 
 		public uint TimeNow { get; set; }
 
@@ -22,8 +24,6 @@ namespace Model
 		
 		private readonly Dictionary<long, KChannel> idChannels = new Dictionary<long, KChannel>();
 
-		private readonly Queue<UdpReceiveResult> udpResults = new Queue<UdpReceiveResult>();
-
 		private TaskCompletionSource<AChannel> acceptTcs;
 
 		private readonly Queue<long> removedChannels = new Queue<long>();
@@ -39,6 +39,12 @@ namespace Model
 		{
 			this.TimeNow = (uint)TimeHelper.Now();
 			this.socket = new UdpClient(ipEndPoint);
+
+			uint IOC_IN = 0x80000000;
+			uint IOC_VENDOR = 0x18000000;
+			uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
+			this.socket.Client.IOControl((int)SIO_UDP_CONNRESET, new[] { Convert.ToByte(false) }, null);
+
 			this.StartRecv();
 		}
 
@@ -68,7 +74,17 @@ namespace Model
 				{
 					return;
 				}
-				UdpReceiveResult udpReceiveResult = await this.socket.ReceiveAsync();
+
+				UdpReceiveResult udpReceiveResult;
+				try
+				{
+					udpReceiveResult = await this.socket.ReceiveAsync();
+				}
+				catch (Exception e)
+				{
+					Log.Error(e.ToString());
+					continue;
+				}
 
 				// accept
 				uint conn = BitConverter.ToUInt32(udpReceiveResult.Buffer, 0);
@@ -87,13 +103,13 @@ namespace Model
 					continue;
 				}
 
-				if (conn < 1000)
+				if (conn == KcpProtocalType.FIN)
 				{
-					Log.Error($"error conn: {conn} {udpReceiveResult.RemoteEndPoint}");
+					this.HandleDisConnect(udpReceiveResult);
 					continue;
 				}
 
-				this.HandleRecv(udpReceiveResult);
+				this.HandleRecv(udpReceiveResult, conn);
 			}
 		}
 
@@ -101,6 +117,7 @@ namespace Model
 		{
 			uint requestConn = BitConverter.ToUInt32(udpReceiveResult.Buffer, 4);
 			uint responseConn = BitConverter.ToUInt32(udpReceiveResult.Buffer, 8);
+			
 			KChannel kChannel;
 			if (!this.idChannels.TryGetValue(requestConn, out kChannel))
 			{
@@ -110,11 +127,22 @@ namespace Model
 			kChannel.HandleConnnect(responseConn);
 		}
 
-		private void HandleRecv(UdpReceiveResult udpReceiveResult)
+		private void HandleDisConnect(UdpReceiveResult udpReceiveResult)
 		{
-			uint conn = 0;
-			Kcp.ikcp_decode32u(udpReceiveResult.Buffer, 0, ref conn);
+			uint requestConn = BitConverter.ToUInt32(udpReceiveResult.Buffer, 8);
+			
+			KChannel kChannel;
+			if (!this.idChannels.TryGetValue(requestConn, out kChannel))
+			{
+				return;
+			}
+			// 处理chanel
+			this.idChannels.Remove(requestConn);
+			kChannel.Dispose();
+		}
 
+		private void HandleRecv(UdpReceiveResult udpReceiveResult, uint conn)
+		{
 			KChannel kChannel;
 			if (!this.idChannels.TryGetValue(conn, out kChannel))
 			{
@@ -128,7 +156,6 @@ namespace Model
 		{
 			if (this.acceptTcs == null)
 			{
-				this.udpResults.Enqueue(udpReceiveResult);
 				return;
 			}
 
@@ -151,7 +178,13 @@ namespace Model
 
 		private KChannel CreateAcceptChannel(IPEndPoint remoteEndPoint, uint remoteConn)
 		{
-			KChannel channel = new KChannel(++this.IdGenerater, remoteConn, this.socket, remoteEndPoint, this);
+			KChannel channel = new KChannel(--this.IdAccept, remoteConn, this.socket, remoteEndPoint, this);
+			KChannel oldChannel;
+			if (this.idChannels.TryGetValue(channel.Id, out oldChannel))
+			{
+				this.idChannels.Remove(oldChannel.Id);
+				oldChannel.Dispose();
+			}
 			this.idChannels[channel.Id] = channel;
 			return channel;
 		}
@@ -159,6 +192,12 @@ namespace Model
 		private KChannel CreateConnectChannel(IPEndPoint remoteEndPoint)
 		{
 			KChannel channel = new KChannel(++this.IdGenerater, this.socket, remoteEndPoint, this);
+			KChannel oldChannel;
+			if (this.idChannels.TryGetValue(channel.Id, out oldChannel))
+			{
+				this.idChannels.Remove(oldChannel.Id);
+				oldChannel.Dispose();
+			}
 			this.idChannels[channel.Id] = channel;
 			return channel;
 		}
@@ -186,14 +225,6 @@ namespace Model
 
 		public override Task<AChannel> AcceptChannel()
 		{
-			if (this.udpResults.Count > 0)
-			{
-				UdpReceiveResult udpReceiveResult = this.udpResults.Dequeue();
-				uint requestConn = BitConverter.ToUInt32(udpReceiveResult.Buffer, 4);
-				KChannel kChannel = this.CreateAcceptChannel(udpReceiveResult.RemoteEndPoint, requestConn);
-				return Task.FromResult<AChannel>(kChannel);
-			}
-
 			acceptTcs = new TaskCompletionSource<AChannel>();
 			return this.acceptTcs.Task;
 		}

+ 3 - 2
Unity/Assets/Scripts/Base/Network/KNet/Kcp.cs

@@ -526,8 +526,9 @@ public class Kcp
 
 			offset += ikcp_decode32u(data, offset, ref conv_);
 
-			if (conv != conv_)
-				return -1;
+			// 这里我做了修改,不判断两端kcp conv相等,因为客户端也需要一个socket支持多个client连接
+			//if (conv != conv_)
+			//	return -1;
 
 			offset += ikcp_decode8u(data, offset, ref cmd);
 			offset += ikcp_decode8u(data, offset, ref frg);

+ 5 - 4
Unity/Hotfix/UI/UILogin/Component/UILoginComponent.cs

@@ -1,5 +1,4 @@
-using System;
-using System.Net;
+using System.Net;
 using Model;
 using UnityEngine;
 using UnityEngine.UI;
@@ -35,11 +34,13 @@ namespace Hotfix
 			IPEndPoint connetEndPoint = NetworkHelper.ToIPEndPoint(GlobalConfigComponent.Instance.GlobalProto.Address);
 			session = Game.Scene.GetComponent<NetOuterComponent>().Create(connetEndPoint);
 			string text = this.account.GetComponent<InputField>().text;
-			session.CallWithAction(new C2R_Login() { Account = text, Password = "111111" }, (response) => LoginOK(response));
+			session.CallWithAction(new C2R_Login() { Account = text, Password = "111111" }, (response) => LoginOK(session, response));
 		}
 
-		private void LoginOK(AResponse response)
+		private void LoginOK(Session loginSession, AResponse response)
 		{
+			loginSession.Dispose();
+
 			R2C_Login r2CLogin = (R2C_Login) response;
 			if (r2CLogin.Error != ErrorCode.ERR_Success)
 			{