diff --git a/HaoYueNet.sln b/HaoYueNet.sln index ae173fb..c02f4e6 100644 --- a/HaoYueNet.sln +++ b/HaoYueNet.sln @@ -23,6 +23,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientCore", "Simple\Client EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client-Cli", "Simple\Client-Cli\Client-Cli.csproj", "{45FBC25D-9EC5-4C8E-A979-005F04CE76AB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HaoYueNet.ServerNetworkNet4x", "NetLib\HaoYueNet.ServerNetworkNet4x\HaoYueNet.ServerNetworkNet4x.csproj", "{036F9BD9-308C-4194-AB40-C5952EF0E9F5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -61,6 +63,10 @@ Global {45FBC25D-9EC5-4C8E-A979-005F04CE76AB}.Debug|Any CPU.Build.0 = Debug|Any CPU {45FBC25D-9EC5-4C8E-A979-005F04CE76AB}.Release|Any CPU.ActiveCfg = Release|Any CPU {45FBC25D-9EC5-4C8E-A979-005F04CE76AB}.Release|Any CPU.Build.0 = Release|Any CPU + {036F9BD9-308C-4194-AB40-C5952EF0E9F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {036F9BD9-308C-4194-AB40-C5952EF0E9F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {036F9BD9-308C-4194-AB40-C5952EF0E9F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {036F9BD9-308C-4194-AB40-C5952EF0E9F5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -74,6 +80,7 @@ Global {3F52D1D0-4B1E-4819-9AB3-A770DD5C505D} = {A2CAD164-0816-4D1D-9793-1B1F398C9D29} {99E54CE5-4EF6-4441-9F40-8FDE8229041E} = {A2CAD164-0816-4D1D-9793-1B1F398C9D29} {45FBC25D-9EC5-4C8E-A979-005F04CE76AB} = {A2CAD164-0816-4D1D-9793-1B1F398C9D29} + {036F9BD9-308C-4194-AB40-C5952EF0E9F5} = {D0066C06-A89A-4E05-80E0-D8232FB0FF3C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {22107F03-013F-4871-AC8E-F082694E2679} diff --git a/NetLib/HaoYueNet.ClientNetworkNet4x/BaseData.cs b/NetLib/HaoYueNet.ClientNetworkNet4x/BaseData.cs index dfb4fef..3e29823 100644 --- a/NetLib/HaoYueNet.ClientNetworkNet4x/BaseData.cs +++ b/NetLib/HaoYueNet.ClientNetworkNet4x/BaseData.cs @@ -1,9 +1,5 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Net.Sockets; -using System.Text; -using System.Threading.Tasks; namespace HaoYueNet.ClientNetworkNet4x { @@ -19,6 +15,7 @@ namespace HaoYueNet.ClientNetworkNet4x buf[offset++] = (byte)(255 & value); buf[offset++] = (byte)(255 & value >> 8); buf[offset++] = (byte)(255 & value >> 16); + //buf[offset++] = (byte)(255 & value >>> 24); buf[offset++] = (byte)(255 & value >> 24); } @@ -40,7 +37,7 @@ namespace HaoYueNet.ClientNetworkNet4x { public static void SetDataToSocketAsyncEventArgs(SocketAsyncEventArgs myreadEventArgs, UInt16 CmdID, UInt16 Error, byte[] AddonBytes_Data) { - byte[] data = CreatePkgData(CmdID, Error, AddonBytes_Data); + byte[] data = CreatePkgData(CmdID, Error, AddonBytes_Data); myreadEventArgs.SetBuffer(data,0, data.Length); } @@ -118,21 +115,13 @@ namespace HaoYueNet.ClientNetworkNet4x return BufferData; } - public static void AnalysisPkgData(Span srcdata, out UInt16 CmdID, out UInt16 Error, out byte[] data) + public static void AnalysisPkgData(byte[] srcdata, out UInt16 CmdID, out UInt16 Error, out byte[] data) { - //CmdID = BitConverter.ToUInt16(srcdata, 0); - //Error = BitConverter.ToUInt16(srcdata, 2); - //data = new byte[srcdata.Length - 2 - 2]; - //Array.Copy(srcdata, 4, data, 0, data.Length); + CmdID = BitConverter.ToUInt16(srcdata, 0); + Error = BitConverter.ToUInt16(srcdata, 2); + data = new byte[srcdata.Length - 2 - 2]; + Array.Copy(srcdata, 4, data, 0, data.Length); - //CmdID = BitConverter.ToUInt16(srcdata, 0); - //Error = BitConverter.ToUInt16(srcdata, 2); - //Span span_srcdata = srcdata; - //data = span_srcdata.Slice(2 + 2).ToArray(); - - CmdID = BitConverter.ToUInt16(srcdata.Slice(0, 2).ToArray(), 0); - Error = BitConverter.ToUInt16(srcdata.Slice(2, 2).ToArray(), 2); - data = srcdata.Slice(2 + 2).ToArray(); } } @@ -146,31 +135,6 @@ namespace HaoYueNet.ClientNetworkNet4x public static byte[] CreatePkgData(UInt16 CmdID, byte[] AddonBytes_Data) { - //byte[] AddonBytes_CmdID = BitConverter.GetBytes(CmdID); - //int AllLenght = AddonBytes_CmdID.Length + AddonBytes_Data.Length + 4; - //int LastIndex = 0; - ////包长度 - //byte[] AddonBytes_Lenght = BitConverter.GetBytes(AllLenght); - - //byte[] BufferData = new byte[AllLenght]; - - ////包长度 - //AddonBytes_Lenght.CopyTo(BufferData, LastIndex); - //LastIndex += AddonBytes_Lenght.Length; - - ////CMDID - //AddonBytes_CmdID.CopyTo(BufferData, LastIndex); - //LastIndex += AddonBytes_CmdID.Length; - - ////DATA - //AddonBytes_Data.CopyTo(BufferData, LastIndex); - //LastIndex += AddonBytes_Data.Length; - - //myreadEventArgs.SetBuffer(BufferData, 0, BufferData.Length); - //return BufferData; - - //用Buffer.BlockCopy拷贝 - byte[] AddonBytes_CmdID = BitConverter.GetBytes(CmdID); int AllLenght = AddonBytes_CmdID.Length + AddonBytes_Data.Length + 4; int LastIndex = 0; @@ -192,18 +156,11 @@ namespace HaoYueNet.ClientNetworkNet4x return BufferData; } - public static void AnalysisPkgData(Span srcdata, out UInt16 CmdID, out byte[] data) + public static void AnalysisPkgData(byte[] srcdata, out UInt16 CmdID, out byte[] data) { - //data = new byte[srcdata.Length - 2]; - //CmdID = BitConverter.ToUInt16(srcdata, 0); - //Array.Copy(srcdata, 2, data, 0, data.Length); - - //CmdID = BitConverter.ToUInt16(srcdata, 0); - //Span span_srcdata = srcdata; - //data = span_srcdata.Slice(2).ToArray(); - - CmdID = BitConverter.ToUInt16(srcdata.Slice(0, 2).ToArray(),0); - data = srcdata.Slice(2).ToArray(); + data = new byte[srcdata.Length - 2]; + CmdID = BitConverter.ToUInt16(srcdata, 0); + Array.Copy(srcdata, 2, data, 0, data.Length); } } } diff --git a/NetLib/HaoYueNet.ClientNetworkNet4x/HaoYueNet.ClientNetworkNet4x.csproj b/NetLib/HaoYueNet.ClientNetworkNet4x/HaoYueNet.ClientNetworkNet4x.csproj index 3d2d14f..2d6a583 100644 --- a/NetLib/HaoYueNet.ClientNetworkNet4x/HaoYueNet.ClientNetworkNet4x.csproj +++ b/NetLib/HaoYueNet.ClientNetworkNet4x/HaoYueNet.ClientNetworkNet4x.csproj @@ -22,6 +22,7 @@ DEBUG;TRACE prompt 4 + false pdbonly @@ -30,6 +31,7 @@ TRACE prompt 4 + false @@ -49,6 +51,8 @@ + + diff --git a/NetLib/HaoYueNet.ClientNetworkNet4x/NetworkHelperCore.cs b/NetLib/HaoYueNet.ClientNetworkNet4x/NetworkHelperCore.cs index 0f55a4f..cde13e8 100644 --- a/NetLib/HaoYueNet.ClientNetworkNet4x/NetworkHelperCore.cs +++ b/NetLib/HaoYueNet.ClientNetworkNet4x/NetworkHelperCore.cs @@ -1,4 +1,5 @@ -using System; +//using HunterProtobufCore; +using System; using System.IO; using System.Net; using System.Net.Sockets; @@ -11,6 +12,13 @@ namespace HaoYueNet.ClientNetworkNet4x { private Socket client; + + ////响应倒计时计数最大值 + //private static int MaxRevIndexNum = 6; + + ////发送倒计时计数最大值 + //private static int MaxSendIndexNum = 3; + //响应倒计时计数最大值 private static int MaxRevIndexNum = 50; @@ -18,9 +26,9 @@ namespace HaoYueNet.ClientNetworkNet4x private static int MaxSendIndexNum = 3; //响应倒计时计数 - private static int RevIndex = 0; + private static int RevIndex=0; //发送倒计时计数 - private static int SendIndex = 0; + private static int SendIndex=0; //计时器间隔 private static int TimerInterval = 3000; @@ -31,7 +39,7 @@ namespace HaoYueNet.ClientNetworkNet4x public static int LastConnectPort; public bool bDetailedLog = false; - public bool Init(string IP, int port, bool isHadDetailedLog = true, bool bBindReuseAddress = false, int bBindport = 0) + public bool Init(string IP, int port,bool isHadDetailedLog = true, bool bBindReuseAddress = false,int bBindport = 0) { LogOut("==>初始化网络核心"); @@ -56,7 +64,7 @@ namespace HaoYueNet.ClientNetworkNet4x //带回调的 try { - if (bDetailedLog) + if(bDetailedLog) LogOut("连接到远程IP " + IP + ":" + port); else LogOut("连接到远程服务"); @@ -136,16 +144,20 @@ namespace HaoYueNet.ClientNetworkNet4x //LogOut("发送心跳包"); } + object sendLock = new object(); /// /// 发送数据并计数 /// /// private void SendWithIndex(byte[] data) { - //增加发送计数 - SendIndex = MaxSendIndexNum; - //发送数据 - client.Send(data); + lock (sendLock) + { + //增加发送计数 + SendIndex = MaxSendIndexNum; + //发送数据 + client.Send(data); + } } ////拼接头长度 @@ -173,7 +185,7 @@ namespace HaoYueNet.ClientNetworkNet4x /// /// /// 序列化之后的数据 - public void SendToServer(int CMDID, byte[] data) + public void SendToServer(int CMDID,byte[] data) { //LogOut("准备数据 CMDID=> "+CMDID); /* @@ -201,24 +213,6 @@ namespace HaoYueNet.ClientNetworkNet4x /// public event OnLogOutHandler OnLogOut; - ///// - ///// 用于调用者回调的虚函数 - ///// - ///// - //public virtual void DataCallBack(int CMDID,int ERRCODE,byte[] data) - //{ - - //} - - ///// - ///// 断开连接 - ///// - ///// - //public virtual void OnClose() - //{ - - //} - /// /// 做好处理的连接管理 /// @@ -235,7 +229,6 @@ namespace HaoYueNet.ClientNetworkNet4x OnClose?.Invoke(); } - /// /// 主动关闭连接 /// @@ -243,7 +236,7 @@ namespace HaoYueNet.ClientNetworkNet4x { OnCloseReady(); } - + private void DataCallBackReady(byte[] data) { @@ -277,7 +270,7 @@ namespace HaoYueNet.ClientNetworkNet4x while (true) { byte[] buffer = new byte[1024 * 1024 * 2]; - int effective = 0; + int effective=0; try { effective = client.Receive(buffer); @@ -286,7 +279,7 @@ namespace HaoYueNet.ClientNetworkNet4x continue; } } - catch (Exception ex) + catch(Exception ex) { //远程主机强迫关闭了一个现有的连接 OnCloseReady(); @@ -344,7 +337,7 @@ namespace HaoYueNet.ClientNetworkNet4x //用Span Span getData_span = getData; - getData_span = getData_span.Slice(StartIndex + 4, CoreLenght); + getData_span = getData_span.Slice(StartIndex + 4,CoreLenght); DataCallBackReady(getData_span.ToArray()); StartIndex += HeadLength;//当读取一条完整的数据后,读取数据的起始下标应为当前接受到的消息体的长度(当前数据的尾部或下一条消息的首部) @@ -389,4 +382,4 @@ namespace HaoYueNet.ClientNetworkNet4x return client; } } -} \ No newline at end of file +} diff --git a/NetLib/HaoYueNet.ClientNetworkNet4x/NetworkHelperP2PCore.cs b/NetLib/HaoYueNet.ClientNetworkNet4x/NetworkHelperP2PCore.cs index 237b2bc..254a45a 100644 --- a/NetLib/HaoYueNet.ClientNetworkNet4x/NetworkHelperP2PCore.cs +++ b/NetLib/HaoYueNet.ClientNetworkNet4x/NetworkHelperP2PCore.cs @@ -18,16 +18,16 @@ namespace HaoYueNet.ClientNetworkNet4x private static int MaxSendIndexNum = 3; //响应倒计时计数 - private static int RevIndex = 0; + private static int RevIndex=0; //发送倒计时计数 - private static int SendIndex = 0; + private static int SendIndex=0; //计时器间隔 private static int TimerInterval = 3000; private System.Timers.Timer _heartTimer; - public void Init(string IP, int port, bool bBindReuseAddress = false, int bBindport = 0) + public void Init(string IP, int port, bool bBindReuseAddress = false,int bBindport = 0) { LogOut("==>初始化网络核心"); @@ -128,25 +128,25 @@ namespace HaoYueNet.ClientNetworkNet4x client.Send(data); } - //拼接头长度 - private byte[] SendDataWithHead(byte[] message) - { + ////拼接头长度 + //private byte[] SendDataWithHead(byte[] message) + //{ - MemoryStream memoryStream = new MemoryStream();//创建一个内存流 + // MemoryStream memoryStream = new MemoryStream();//创建一个内存流 - byte[] BagHead = BitConverter.GetBytes(message.Length + 4);//往字节数组中写入包头(包头自身的长度和消息体的长度)的长度 + // byte[] BagHead = BitConverter.GetBytes(message.Length + 4);//往字节数组中写入包头(包头自身的长度和消息体的长度)的长度 - memoryStream.Write(BagHead, 0, BagHead.Length);//将包头写入内存流 + // memoryStream.Write(BagHead, 0, BagHead.Length);//将包头写入内存流 - memoryStream.Write(message, 0, message.Length);//将消息体写入内存流 + // memoryStream.Write(message, 0, message.Length);//将消息体写入内存流 - byte[] HeadAndBody = memoryStream.ToArray();//将内存流中的数据写入字节数组 + // byte[] HeadAndBody = memoryStream.ToArray();//将内存流中的数据写入字节数组 - memoryStream.Close();//关闭内存 - memoryStream.Dispose();//释放资源 + // memoryStream.Close();//关闭内存 + // memoryStream.Dispose();//释放资源 - return HeadAndBody; - } + // return HeadAndBody; + //} /// /// 供外部调用 发送消息 @@ -226,7 +226,7 @@ namespace HaoYueNet.ClientNetworkNet4x { OnCloseReady(); } - + private void DataCallBackReady(byte[] data) { @@ -257,7 +257,7 @@ namespace HaoYueNet.ClientNetworkNet4x while (true) { byte[] buffer = new byte[1024 * 1024 * 2]; - int effective = 0; + int effective=0; try { effective = client.Receive(buffer); @@ -266,7 +266,7 @@ namespace HaoYueNet.ClientNetworkNet4x continue; } } - catch (Exception ex) + catch(Exception ex) { //远程主机强迫关闭了一个现有的连接 OnCloseReady(); diff --git a/NetLib/HaoYueNet.ClientNetworkNet4x/OtherMode/NetworkHelperCore_ListenerMode.cs b/NetLib/HaoYueNet.ClientNetworkNet4x/OtherMode/NetworkHelperCore_ListenerMode.cs new file mode 100644 index 0000000..eae28e4 --- /dev/null +++ b/NetLib/HaoYueNet.ClientNetworkNet4x/OtherMode/NetworkHelperCore_ListenerMode.cs @@ -0,0 +1,241 @@ +using System.Net; +using System.Net.Sockets; +using static HaoYueNet.ClientNetworkNet4x.BaseData; +using System.Collections.Generic; +using System.Threading.Tasks; +using System; +using System.IO; +using System.Threading; +using System.Linq; + +namespace HaoYueNet.ClientNetwork.OtherMode +{ + public class NetworkHelperCore_ListenerMode + { + private Socket serversocket; + private Dictionary mDictHandleClient; + + //响应倒计时计数最大值 + private static int MaxRevIndexNum = 50; + + //发送倒计时计数最大值 + private static int MaxSendIndexNum = 3; + + //响应倒计时计数 + private static int RevIndex = 0; + //发送倒计时计数 + private static int SendIndex = 0; + //计时器间隔 + private static int TimerInterval = 3000; + + public static string LastConnectIP; + public static int LastConnectPort; + public bool bDetailedLog = false; + + public void Init(int port) + { + mDictHandleClient = new Dictionary(); + + LogOut("==>初始化NetworkHelperCore_ListenerMode"); + serversocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, port); + serversocket.Bind(endPoint); // 绑定 + serversocket.Listen(1); + //client = serversocket.Accept(); // 接收客户端连接 + //OnConnected?.Invoke(true); + //Console.WriteLine("客户端连接成功 信息: " + client.AddressFamily.ToString()); + //Thread revThread = new Thread(Recive); + //revThread.Start(client); + + Task task = new Task(() => + { + while (true) + { + Socket newclient; + try + { + newclient = serversocket.Accept(); // 接收客户端连接 + } + catch + { + break; + } + AddDictSocket(newclient); + OnConnected?.Invoke(newclient); + Console.WriteLine("客户端连接成功 信息: " + newclient.AddressFamily.ToString()); + Thread revThread = new Thread(Recive); + revThread.Start(newclient); + } + }); + task.Start(); + } + +#region + + /// + /// 追加Socket返回下标 + /// + /// + /// + public void AddDictSocket(Socket socket) + { + if (socket == null) + return; + lock (mDictHandleClient) + { + mDictHandleClient[socket.Handle] = socket; + } + } + + public void RemoveDictSocket(Socket socket) + { + if (socket == null) + return; + lock (mDictHandleClient) + { + if (!mDictHandleClient.ContainsKey(socket.Handle)) + return; + mDictHandleClient.Remove(socket.Handle); + } + } +#endregion + + ~NetworkHelperCore_ListenerMode() + { + IntPtr[] keys = mDictHandleClient.Keys.ToArray(); + for (uint i = 0; i < keys.Length; i++) + { + mDictHandleClient[keys[i]].Close(); + } + mDictHandleClient.Clear(); + } + + private void SendToSocket(Socket socket, byte[] data) + { + //已拼接包长度,这里不再需要拼接长度 + //data = SendDataWithHead(data); + try + { + SendWithIndex(socket,data); + } + catch (Exception ex) + { + //连接断开 + OnCloseReady(socket); + return; + } + //LogOut("发送消息,消息长度=> "+data.Length); + } + + /// + /// 发送数据并计数 + /// + /// + private void SendWithIndex(Socket socket,byte[] data) + { + //增加发送计数 + SendIndex = MaxSendIndexNum; + //发送数据 + socket.Send(data); + } + + /// + /// 供外部调用 发送消息 + /// + /// + /// 序列化之后的数据 + public void SendToClient(Socket socket, byte[] data) + { + //LogOut("准备数据 data=> "+data); + SendToSocket(socket, data); + } + +#region 事件定义 + public delegate void OnConnectedHandler(Socket socket); + + public delegate void OnReceiveDataHandler(Socket sk, byte[] data); + + public delegate void OnDisconnectHandler(Socket sk); + + public delegate void OnNetLogHandler(string msg); +#endregion + + public event OnConnectedHandler OnConnected; + + public event OnReceiveDataHandler OnReceive; + + public event OnDisconnectHandler OnDisconnected; + + public event OnNetLogHandler OnNetLog; + + /// + /// 做好处理的连接管理 + /// + private void OnCloseReady(Socket socket) + { + LogOut("关闭连接"); + //关闭Socket连接 + socket.Close(); + RemoveDictSocket(socket); + OnDisconnected?.Invoke(socket); + } + + /// + /// 主动关闭连接 + /// + public void CloseConntect(Socket socket) + { + OnCloseReady(socket); + } + + private void DataCallBackReady(Socket socket,byte[] data) + { + //增加接收计数 + RevIndex = MaxRevIndexNum; + OnReceive(socket,data); + } + + private void Recive(object o) + { + MemoryStream memoryStream = new MemoryStream();//开辟一个内存流 + var client = o as Socket; + //MemoryStream memoryStream = new MemoryStream();//开辟一个内存流 + + while (true) + { + byte[] buffer = new byte[1024 * 1024 * 2]; + int effective = 0; + try + { + effective = client.Receive(buffer); + if (effective == 0) + { + continue; + } + } + catch (Exception ex) + { + //远程主机强迫关闭了一个现有的连接 + OnCloseReady(client); + return; + //断开连接 + } + if (effective > 0)//如果接受到的消息不为0(不为空) + { + memoryStream.Write(buffer, 0, effective);//将接受到的数据写入内存流中 + DataCallBackReady(client, memoryStream.ToArray()); + //流复用的方式 不用重新new申请 + memoryStream.Position = 0; + memoryStream.SetLength(0); + } + } + } + + public void LogOut(string Msg) + { + //Console.WriteLine(Msg); + OnNetLog?.Invoke(Msg); + } + + } +} diff --git a/NetLib/HaoYueNet.ClientNetworkNet4x/OtherMode/NetworkHelperCore_SourceMode.cs b/NetLib/HaoYueNet.ClientNetworkNet4x/OtherMode/NetworkHelperCore_SourceMode.cs new file mode 100644 index 0000000..6a320fe --- /dev/null +++ b/NetLib/HaoYueNet.ClientNetworkNet4x/OtherMode/NetworkHelperCore_SourceMode.cs @@ -0,0 +1,246 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using static HaoYueNet.ClientNetworkNet4x.BaseData; + +namespace HaoYueNet.ClientNetwork.OtherMode +{ + public class NetworkHelperCore_SourceMode + { + private Socket client; + + ////响应倒计时计数最大值 + //private static int MaxRevIndexNum = 6; + + ////发送倒计时计数最大值 + //private static int MaxSendIndexNum = 3; + + //响应倒计时计数最大值 + private static int MaxRevIndexNum = 50; + + //发送倒计时计数最大值 + private static int MaxSendIndexNum = 3; + + //响应倒计时计数 + private static int RevIndex = 0; + //发送倒计时计数 + private static int SendIndex = 0; + + //计时器间隔 + private static int TimerInterval = 3000; + + public static string LastConnectIP; + public static int LastConnectPort; + public bool bDetailedLog = false; + + public bool Init(string IP, int port, bool isHadDetailedLog = true, bool bBindReuseAddress = false, int bBindport = 0) + { + LogOut("==>初始化网络核心"); + + bDetailedLog = isHadDetailedLog; + RevIndex = MaxRevIndexNum; + SendIndex = MaxSendIndexNum; + + client = new Socket(SocketType.Stream, ProtocolType.Tcp); + if (bBindReuseAddress) + { + client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + IPEndPoint ipe = new IPEndPoint(IPAddress.Any, Convert.ToInt32(bBindport)); + client.Bind(ipe); + } + LastConnectIP = IP; + LastConnectPort = port; + return Connect(IP, port); + } + + bool Connect(string IP, int port) + { + //带回调的 + try + { + if (bDetailedLog) + LogOut("连接到远程IP " + IP + ":" + port); + else + LogOut("连接到远程服务"); + + client.Connect(IP, port); + Thread thread = new Thread(Recive); + thread.IsBackground = true; + thread.Start(client); + int localport = ((IPEndPoint)client.LocalEndPoint).Port; + + if (bDetailedLog) + LogOut($"连接成功!连接到远程IP->{IP}:{port} | 本地端口->{localport}"); + else + LogOut("连接成功!"); + + if (bDetailedLog) + LogOut("开启心跳包检测"); + + OnConnected?.Invoke(true); + return true; + } + catch (Exception ex) + { + if (bDetailedLog) + LogOut("连接失败:" + ex.ToString()); + else + LogOut("连接失败"); + + OnConnected?.Invoke(false); + return false; + } + } + + ~NetworkHelperCore_SourceMode() + { + client.Close(); + } + + private void SendToSocket(byte[] data) + { + //已拼接包长度,这里不再需要拼接长度 + //data = SendDataWithHead(data); + try + { + SendWithIndex(data); + } + catch (Exception ex) + { + //连接断开 + OnCloseReady(); + return; + } + //LogOut("发送消息,消息长度=> "+data.Length); + } + + private void SendHeartbeat() + { + try + { + SendWithIndex(HeartbeatData); + } + catch (Exception ex) + { + //连接断开 + OnCloseReady(); + return; + } + //LogOut("发送心跳包"); + } + + /// + /// 发送数据并计数 + /// + /// + private void SendWithIndex(byte[] data) + { + //增加发送计数 + SendIndex = MaxSendIndexNum; + //发送数据 + client.Send(data); + } + + /// + /// 供外部调用 发送消息 + /// + /// + /// 序列化之后的数据 + public void SendToServer(byte[] data) + { + //LogOut("准备数据 data=> "+data); + SendToSocket(data); + } + + #region 事件定义 + public delegate void OnReceiveDataHandler(byte[] data); + public delegate void OnConnectedHandler(bool IsConnected); + public delegate void OnCloseHandler(); + public delegate void OnLogOutHandler(string Msg); + #endregion + + public event OnConnectedHandler OnConnected; + public event OnReceiveDataHandler OnReceiveData; + public event OnCloseHandler OnClose; + /// + /// 网络库调试日志输出 + /// + public event OnLogOutHandler OnLogOut; + + /// + /// 做好处理的连接管理 + /// + private void OnCloseReady() + { + LogOut("关闭连接"); + //关闭Socket连接 + client.Close(); + OnClose?.Invoke(); + } + + /// + /// 主动关闭连接 + /// + public void CloseConntect() + { + OnCloseReady(); + } + + private void DataCallBackReady(byte[] data) + { + //增加接收计数 + RevIndex = MaxRevIndexNum; + OnReceiveData(data); + } + + MemoryStream memoryStream = new MemoryStream();//开辟一个内存流 + private void Recive(object o) + { + var client = o as Socket; + //MemoryStream memoryStream = new MemoryStream();//开辟一个内存流 + + while (true) + { + byte[] buffer = new byte[1024 * 1024 * 2]; + int effective = 0; + try + { + effective = client.Receive(buffer); + if (effective == 0) + { + continue; + } + } + catch (Exception ex) + { + //远程主机强迫关闭了一个现有的连接 + OnCloseReady(); + return; + //断开连接 + } + if (effective > 0)//如果接受到的消息不为0(不为空) + { + memoryStream.Write(buffer, 0, effective);//将接受到的数据写入内存流中 + DataCallBackReady(memoryStream.ToArray()); + //流复用的方式 不用重新new申请 + memoryStream.Position = 0; + memoryStream.SetLength(0); + } + } + } + + + public void LogOut(string Msg) + { + //Console.WriteLine(Msg); + OnLogOut?.Invoke(Msg); + } + + public Socket GetClientSocket() + { + return client; + } + } +} diff --git a/NetLib/HaoYueNet.ClientNetworkNet4x/Properties/AssemblyInfo.cs b/NetLib/HaoYueNet.ClientNetworkNet4x/Properties/AssemblyInfo.cs index 0e0b53f..2f7d5bf 100644 --- a/NetLib/HaoYueNet.ClientNetworkNet4x/Properties/AssemblyInfo.cs +++ b/NetLib/HaoYueNet.ClientNetworkNet4x/Properties/AssemblyInfo.cs @@ -5,11 +5,11 @@ using System.Runtime.InteropServices; // 有关程序集的一般信息由以下 // 控制。更改这些特性值可修改 // 与程序集关联的信息。 -[assembly: AssemblyTitle("HaoYueNet.ClientNetworkNet4x")] +[assembly: AssemblyTitle("HaoYueNet.ClientNetworkNet4x4x4x")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("HaoYueNet.ClientNetworkNet4x")] +[assembly: AssemblyProduct("HaoYueNet.ClientNetworkNet4x4x4x")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/NetLib/HaoYueNet.ServerNetworkNet4x/BaseData.cs b/NetLib/HaoYueNet.ServerNetworkNet4x/BaseData.cs new file mode 100644 index 0000000..c73e330 --- /dev/null +++ b/NetLib/HaoYueNet.ServerNetworkNet4x/BaseData.cs @@ -0,0 +1,167 @@ +using System; +using System.Net.Sockets; + +namespace HaoYueNet.ServerNetworkNet4x +{ + public static class BaseData + { + /// + /// 心跳包数据 + /// + public static byte[] HeartbeatData = new byte[5] { 0x05, 0x00, 0x00, 0x00, 0x00 }; + + public static void writeInt(byte[] buf, int offset, int value) + { + buf[offset++] = (byte)(255 & value); + buf[offset++] = (byte)(255 & value >> 8); + buf[offset++] = (byte)(255 & value >> 16); + //buf[offset++] = (byte)(255 & value >>> 24); + buf[offset++] = (byte)(255 & value >> 24); + } + + public static void writeUInt16(byte[] buf, int offset, int value) + { + buf[offset++] = (byte)(255 & value); + buf[offset++] = (byte)(255 & value >> 8); + } + + public static class HunterNet_Heartbeat + { + public static void SetDataToSocketAsyncEventArgs(SocketAsyncEventArgs myreadEventArgs) + { + myreadEventArgs.SetBuffer(HeartbeatData, 0, HeartbeatData.Length); + } + } + + public static class HunterNet_S2C + { + public static void SetDataToSocketAsyncEventArgs(SocketAsyncEventArgs myreadEventArgs, UInt16 CmdID, UInt16 Error, byte[] AddonBytes_Data) + { + byte[] data = CreatePkgData(CmdID, Error, AddonBytes_Data); + myreadEventArgs.SetBuffer(data, 0, data.Length); + } + + public static byte[] CreatePkgData(UInt16 CmdID, UInt16 Error, byte[] AddonBytes_Data) + { + //byte[] AddonBytes_CmdID = BitConverter.GetBytes(CmdID); + //byte[] AddonBytes_Error = BitConverter.GetBytes(Error); + //int AllLenght = AddonBytes_CmdID.Length + AddonBytes_Error.Length + AddonBytes_Data.Length + 4; + //int LastIndex = 0; + ////包长度 + //byte[] AddonBytes_Lenght = BitConverter.GetBytes(AllLenght); + + //byte[] BufferData = new byte[AllLenght]; + ////包长度 + //AddonBytes_Lenght.CopyTo(BufferData, LastIndex); + //LastIndex += AddonBytes_Lenght.Length; + + ////CMDID + //AddonBytes_CmdID.CopyTo(BufferData, LastIndex); + //LastIndex += AddonBytes_CmdID.Length; + + ////Error + //AddonBytes_Error.CopyTo(BufferData, LastIndex); + //LastIndex += AddonBytes_Error.Length; + + ////DATA + //AddonBytes_Data.CopyTo(BufferData, LastIndex); + //LastIndex += AddonBytes_Data.Length; + //return BufferData; + + ////用Buffer.BlockCopy拷贝 + //byte[] AddonBytes_CmdID = BitConverter.GetBytes(CmdID); + //byte[] AddonBytes_Error = BitConverter.GetBytes(Error); + //int AllLenght = AddonBytes_CmdID.Length + AddonBytes_Error.Length + AddonBytes_Data.Length + 4; + //int LastIndex = 0; + ////包长度 + //byte[] AddonBytes_Lenght = BitConverter.GetBytes(AllLenght); + + //byte[] BufferData = new byte[AllLenght]; + ////包长度 + //Buffer.BlockCopy(AddonBytes_Lenght, 0, BufferData, LastIndex, AddonBytes_Lenght.Length); + //LastIndex += AddonBytes_Lenght.Length; + + ////CMDID + //Buffer.BlockCopy(AddonBytes_CmdID, 0, BufferData, LastIndex, AddonBytes_CmdID.Length); + //LastIndex += AddonBytes_CmdID.Length; + + ////Error + //Buffer.BlockCopy(AddonBytes_Error, 0, BufferData, LastIndex, AddonBytes_Error.Length); + //LastIndex += AddonBytes_Error.Length; + + ////DATA + //Buffer.BlockCopy(AddonBytes_Data, 0, BufferData, LastIndex, AddonBytes_Data.Length); + //LastIndex += AddonBytes_Data.Length; + + + + //用Buffer.BlockCopy拷贝 + //包长度 + int AllLenght = 4 + 2 + 2 + AddonBytes_Data.Length; + byte[] BufferData = new byte[AllLenght]; + + //包长度 + writeInt(BufferData, 0, AllLenght); + + //CMDID + writeUInt16(BufferData, 4, CmdID); + + //Error + writeUInt16(BufferData, 4 + 2, CmdID); + + //DATA + Buffer.BlockCopy(AddonBytes_Data, 0, BufferData, 4 + 2 + 2, AddonBytes_Data.Length); + + return BufferData; + } + + public static void AnalysisPkgData(byte[] srcdata, out UInt16 CmdID, out UInt16 Error, out byte[] data) + { + CmdID = BitConverter.ToUInt16(srcdata, 0); + Error = BitConverter.ToUInt16(srcdata, 2); + data = new byte[srcdata.Length - 2 - 2]; + Array.Copy(srcdata, 4, data, 0, data.Length); + + } + } + + public static class HunterNet_C2S + { + public static void SetDataToSocketAsyncEventArgs(SocketAsyncEventArgs myreadEventArgs, UInt16 CmdID, byte[] AddonBytes_Data) + { + byte[] data = CreatePkgData(CmdID, AddonBytes_Data); + myreadEventArgs.SetBuffer(data, 0, data.Length); + } + + public static byte[] CreatePkgData(UInt16 CmdID, byte[] AddonBytes_Data) + { + byte[] AddonBytes_CmdID = BitConverter.GetBytes(CmdID); + int AllLenght = AddonBytes_CmdID.Length + AddonBytes_Data.Length + 4; + int LastIndex = 0; + //包长度 + byte[] AddonBytes_Lenght = BitConverter.GetBytes(AllLenght); + + byte[] BufferData = new byte[AllLenght]; + //包长度 + Buffer.BlockCopy(AddonBytes_Lenght, 0, BufferData, LastIndex, AddonBytes_Lenght.Length); + LastIndex += AddonBytes_Lenght.Length; + + //CMDID + Buffer.BlockCopy(AddonBytes_CmdID, 0, BufferData, LastIndex, AddonBytes_CmdID.Length); + LastIndex += AddonBytes_CmdID.Length; + + //DATA + Buffer.BlockCopy(AddonBytes_Data, 0, BufferData, LastIndex, AddonBytes_Data.Length); + LastIndex += AddonBytes_Data.Length; + return BufferData; + } + + public static void AnalysisPkgData(byte[] srcdata, out UInt16 CmdID, out byte[] data) + { + data = new byte[srcdata.Length - 2]; + CmdID = BitConverter.ToUInt16(srcdata, 0); + Array.Copy(srcdata, 2, data, 0, data.Length); + } + } + } +} diff --git a/NetLib/HaoYueNet.ServerNetworkNet4x/HaoYueNet.ServerNetworkNet4x.csproj b/NetLib/HaoYueNet.ServerNetworkNet4x/HaoYueNet.ServerNetworkNet4x.csproj new file mode 100644 index 0000000..533fc70 --- /dev/null +++ b/NetLib/HaoYueNet.ServerNetworkNet4x/HaoYueNet.ServerNetworkNet4x.csproj @@ -0,0 +1,57 @@ + + + + + Debug + AnyCPU + {036F9BD9-308C-4194-AB40-C5952EF0E9F5} + Library + Properties + HaoYueNet.ServerNetworkNet4X + HaoYueNet.ServerNetworkNet4X + v4.5.2 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/AsyncUserToken.cs b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/AsyncUserToken.cs new file mode 100644 index 0000000..e467d21 --- /dev/null +++ b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/AsyncUserToken.cs @@ -0,0 +1,56 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; + +namespace HaoYueNet.ServerNetworkNet4x +{ + public class AsyncUserToken + { + /// + /// 客户端IP地址 + /// + public IPAddress IPAddress { get; set; } + + /// + /// 远程地址 + /// + public EndPoint Remote { get; set; } + + /// + /// 通信SOKET + /// + public Socket Socket { get; set; } + + /// + /// 连接时间 + /// + public DateTime ConnectTime { get; set; } + + /// + /// 所属用户信息 + /// + public object UserInfo { get; set; } + + /// + /// 数据缓存区 + /// + //public List Buffer { get; set; } + + public MemoryStream memoryStream { get; set; } + + public AsyncUserToken() + { + //this.Buffer = new List(); + this.memoryStream = new MemoryStream(); + } + /// + /// 响应倒计时计数 + /// + public int RevIndex { get; set; } = 0; + /// + /// 发送倒计时计数 + /// + public int SendIndex { get; set; } = 0; + } +} diff --git a/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/BufferManager.cs b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/BufferManager.cs new file mode 100644 index 0000000..13b1ec7 --- /dev/null +++ b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/BufferManager.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using System.Net.Sockets; + +namespace HaoYueNet.ServerNetworkNet4x +{ + public class BufferManager + { + int m_numBytes; // the total number of bytes controlled by the buffer pool + byte[] m_buffer; // the underlying byte array maintained by the Buffer Manager + Stack m_freeIndexPool; // + int m_currentIndex; + int m_bufferSize; + + public BufferManager(int totalBytes, int bufferSize) + { + m_numBytes = totalBytes; + m_currentIndex = 0; + m_bufferSize = bufferSize; + m_freeIndexPool = new Stack(); + } + + // Allocates buffer space used by the buffer pool + public void InitBuffer() + { + // create one big large buffer and divide that + // out to each SocketAsyncEventArg object + m_buffer = new byte[m_numBytes]; + } + + // Assigns a buffer from the buffer pool to the + // specified SocketAsyncEventArgs object + // + // true if the buffer was successfully set, else false + public bool SetBuffer(SocketAsyncEventArgs args) + { + + if (m_freeIndexPool.Count > 0) + { + args.SetBuffer(m_buffer, m_freeIndexPool.Pop(), m_bufferSize); + } + else + { + if ((m_numBytes - m_bufferSize) < m_currentIndex) + { + return false; + } + args.SetBuffer(m_buffer, m_currentIndex, m_bufferSize); + m_currentIndex += m_bufferSize; + } + return true; + } + + // Removes the buffer from a SocketAsyncEventArg object. + // This frees the buffer back to the buffer pool + public void FreeBuffer(SocketAsyncEventArgs args) + { + m_freeIndexPool.Push(args.Offset); + args.SetBuffer(null, 0, 0); + } + } +} diff --git a/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/MemoryStreamPool.cs b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/MemoryStreamPool.cs new file mode 100644 index 0000000..f8dbab1 --- /dev/null +++ b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/MemoryStreamPool.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace HaoYueNet.ServerNetworkNet4x +{ + + public class MemoryStreamPool + { + Stack m_pool; + + public MemoryStreamPool(int capacity) + { + m_pool = new Stack(capacity); + } + + public void Push(MemoryStream item) + { + if (item == null) { throw new ArgumentNullException("Items added to a MemoryStream cannot be null"); } + lock (m_pool) + { + m_pool.Push(item); + } + } + public MemoryStream Pop() + { + lock (m_pool) + { + return m_pool.Pop(); + } + } + + public int Count + { + get { return m_pool.Count; } + } + + public void Clear() + { + m_pool.Clear(); + } + } +} diff --git a/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/SocketEventPool.cs b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/SocketEventPool.cs new file mode 100644 index 0000000..5fc9840 --- /dev/null +++ b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/SocketEventPool.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Net.Sockets; + +namespace HaoYueNet.ServerNetworkNet4x +{ + + public class SocketEventPool + { + Stack m_pool; + + public SocketEventPool(int capacity) + { + m_pool = new Stack(capacity); + } + + public void Push(SocketAsyncEventArgs item) + { + if (item == null) { throw new ArgumentNullException("Items added to a SocketAsyncEventArgsPool cannot be null"); } + lock (m_pool) + { + m_pool.Push(item); + } + } + + // Removes a SocketAsyncEventArgs instance from the pool + // and returns the object removed from the pool + public SocketAsyncEventArgs Pop() + { + lock (m_pool) + { + return m_pool.Pop(); + } + } + + // The number of SocketAsyncEventArgs instances in the pool + public int Count + { + get { return m_pool.Count; } + } + + public void Clear() + { + m_pool.Clear(); + } + } +} diff --git a/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/SourceMode/TcpSaeaServer_SourceMode.cs b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/SourceMode/TcpSaeaServer_SourceMode.cs new file mode 100644 index 0000000..ec675c5 --- /dev/null +++ b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/SourceMode/TcpSaeaServer_SourceMode.cs @@ -0,0 +1,679 @@ +//using HunterProtobufCore; +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using static HaoYueNet.ServerNetworkNet4x.BaseData; + +namespace HaoYueNet.ServerNetworkNet4x +{ + public class TcpSaeaServer_SourceMode + { + #region 定义属性 + protected int MaxRevIndexNum = 50;//响应倒计时计数最大值 + protected int MaxSendIndexNum = 3;//发送倒计时计数最大值 + protected static int TimerInterval = 3000;//计时器间隔 + //protected System.Timers.Timer _heartTimer;//心跳包计数器 + public int m_maxConnectNum; //最大连接数 + public int m_revBufferSize; //最大接收字节数 + protected BufferManager m_bufferManager; + protected const int opsToAlloc = 2; + Socket listenSocket; //监听Socket + protected SocketEventPool m_Receivepool; + protected SocketEventPool m_Sendpool; + protected TokenMsgPool_SourceMode msg_pool; + protected int m_clientCount; //连接的客户端数量 + protected Semaphore m_maxNumberAcceptedClients;//信号量 + protected Dictionary _DictSocketAsyncUserToken = new Dictionary(); + List m_clients; //客户端列表 + public List ClientList { private set { m_clients = value; } get { return m_clients; } } //获取客户端列表 + #endregion + + #region 定义委托 + /// + /// 客户端连接数量变化时触发 + /// + /// 当前增加客户的个数(用户退出时为负数,增加时为正数,一般为1) + /// 增加用户的信息 + public delegate void OnClientNumberChangeHandler(int num, AsyncUserToken token); + /// + /// 接收到客户端的数据 + /// + /// 客户端 + /// 客户端数据 + public delegate void OnReceiveDataHandler(AsyncUserToken sk, byte[] data); + /// + /// 断开连接 + /// + /// + public delegate void OnDisconnectHandler(AsyncUserToken sk); + /// + /// 日志 + /// + /// + public delegate void OnNetLogHandler(string msg); + #endregion + + #region 定义事件 + /// + /// 客户端连接数量变化事件 + /// + public event OnClientNumberChangeHandler OnClientNumberChange; + /// + /// 接收到客户端的数据事件 + /// + public event OnReceiveDataHandler OnReceive; + /// + /// 接收到客户端的断开连接 + /// + public event OnDisconnectHandler OnDisconnected; + /// + /// 网络库内部输出 + /// + public event OnNetLogHandler OnNetLog; + #endregion + + /// + /// 构造函数 + /// + /// 最大连接数 + /// 缓存区大小 + public TcpSaeaServer_SourceMode(int numConnections, int receiveBufferSize) + { + m_clientCount = 0; + m_maxConnectNum = numConnections; + m_revBufferSize = receiveBufferSize; + // allocate buffers such that the maximum number of sockets can have one outstanding read and + //write posted to the socket simultaneously + m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToAlloc, receiveBufferSize); + + m_Receivepool = new SocketEventPool(numConnections); + m_Sendpool = new SocketEventPool(numConnections); + + msg_pool = new TokenMsgPool_SourceMode(numConnections); + + m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections); + } + + #region Client操作 + /// + /// 初始化 + /// + public void Init() + { + // Allocates one large byte buffer which all I/O operations use a piece of. This gaurds + // against memory fragmentation + m_bufferManager.InitBuffer(); + m_clients = new List(); + // preallocate pool of SocketAsyncEventArgs objects + SocketAsyncEventArgs readWriteEventArg; + + for (int i = 0; i < m_maxConnectNum; i++) + { + readWriteEventArg = new SocketAsyncEventArgs(); + readWriteEventArg.Completed += new EventHandler(IO_Completed); + readWriteEventArg.UserToken = new AsyncUserToken(); + // assign a byte buffer from the buffer pool to the SocketAsyncEventArg object + m_bufferManager.SetBuffer(readWriteEventArg); + // add SocketAsyncEventArg to the pool + m_Receivepool.Push(readWriteEventArg); + } + + for (int i = 0; i < m_maxConnectNum; i++) + { + readWriteEventArg = new SocketAsyncEventArgs(); + readWriteEventArg.Completed += new EventHandler(IO_Completed); + readWriteEventArg.UserToken = new AsyncUserToken(); + + //发送是否需要如此设置 TODO + m_bufferManager.SetBuffer(readWriteEventArg); + + m_Sendpool.Push(readWriteEventArg); + } + OutNetLog("初始化完毕"); + } + /// + /// 启动服务 + /// + /// + /// 是否端口重用 + /// + public bool Start(IPEndPoint localEndPoint, bool bReuseAddress = false) + { + try + { + ClearUserToken(); + listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + + if (bReuseAddress) + { + listenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + } + + listenSocket.Bind(localEndPoint); + // start the server with a listen backlog of 100 connections + listenSocket.Listen(m_maxConnectNum); + // post accepts on the listening socket + StartAccept(null); + + OutNetLog("监听:" + listenSocket.LocalEndPoint.ToString()); + + //_heartTimer = new System.Timers.Timer(); + //_heartTimer.Interval = TimerInterval; + //_heartTimer.Elapsed += CheckUpdatetimer_Elapsed; + //_heartTimer.AutoReset = true; + //_heartTimer.Enabled = true; + //OutNetLog("开启定时心跳包"); + + return true; + } + catch (Exception) + { + return false; + } + } + /// + /// 停止服务 + /// + public void Stop() + { + foreach (AsyncUserToken token in m_clients) + { + try + { + token.Socket.Shutdown(SocketShutdown.Both); + } + catch (Exception) { } + } + try + { + listenSocket.Shutdown(SocketShutdown.Both); + } + catch (Exception) { } + + listenSocket.Close(); + int c_count = m_clients.Count; + ClearUserToken(); + + if (OnClientNumberChange != null) + OnClientNumberChange(-c_count, null); + } + public void CloseClient(AsyncUserToken token) + { + try {token.Socket.Shutdown(SocketShutdown.Both);} + catch (Exception) { } + } + /// + /// 关闭客户端连接 + /// + /// + void CloseClientSocket(SocketAsyncEventArgs e) + { + AsyncUserToken token = e.UserToken as AsyncUserToken; + CloseReady(token); + // 释放SocketAsyncEventArg,以便其他客户端可以重用它们 + ReleaseSocketAsyncEventArgs(e); + } + void CloseReady(AsyncUserToken token) + { + OnDisconnected?.Invoke(token); + RemoveUserToken(token); + //如果有事件,则调用事件,发送客户端数量变化通知 + OnClientNumberChange?.Invoke(-1, token); + // 关闭与客户端关联的套接字 + try { token.Socket.Shutdown(SocketShutdown.Send); } catch (Exception) { } + token.Socket.Close(); + // 递减计数器以跟踪连接到服务器的客户端总数 + Interlocked.Decrement(ref m_clientCount); + m_maxNumberAcceptedClients.Release(); + } + #endregion + + #region Token管理 + public AsyncUserToken GetAsyncUserTokenForSocket(Socket sk) + { + return _DictSocketAsyncUserToken.ContainsKey(sk) ? _DictSocketAsyncUserToken[sk] : null; + } + void AddUserToken(AsyncUserToken userToken) + { + lock (_DictSocketAsyncUserToken) + { + m_clients.Add(userToken); + _DictSocketAsyncUserToken.Add(userToken.Socket, userToken); + } + } + void RemoveUserToken(AsyncUserToken userToken) + { + lock (_DictSocketAsyncUserToken) + { + m_clients.Remove(userToken); + _DictSocketAsyncUserToken.Remove(userToken.Socket); + } + } + void ClearUserToken() + { + lock (_DictSocketAsyncUserToken) + { + m_clients.Clear(); + _DictSocketAsyncUserToken.Clear(); + } + } + /// + /// 回收SocketAsyncEventArgs + /// + /// + /// + void ReleaseSocketAsyncEventArgs(SocketAsyncEventArgs saea) + { + //saea.UserToken = null;//TODO + //saea.SetBuffer(null, 0, 0); + //saea.Dispose(); + //↑ 这里不要自作主张去清东西,否则回收回去不可用 + + switch (saea.LastOperation) + { + case SocketAsyncOperation.Receive: + m_Receivepool.Push(saea); + break; + case SocketAsyncOperation.Send: + m_Sendpool.Push(saea); + break; + default: + throw new ArgumentException("ReleaseSocketAsyncEventArgs > The last operation completed on the socket was not a receive or send"); + } + + } + #endregion + + #region 监听IOCP循环 + /// + /// 开始接受客户端的连接请求的操作 + /// + /// 在服务器的侦听套接字上发出接受操作时要使用的上下文对象 + public void StartAccept(SocketAsyncEventArgs acceptEventArg) + { + if (acceptEventArg == null) + { + acceptEventArg = new SocketAsyncEventArgs(); + acceptEventArg.Completed += new EventHandler(AcceptEventArg_Completed); + } + else + { + // socket must be cleared since the context object is being reused + acceptEventArg.AcceptSocket = null; + } + + m_maxNumberAcceptedClients.WaitOne(); + if (!listenSocket.AcceptAsync(acceptEventArg)) + { + ProcessAccept(acceptEventArg); + } + } + /// + /// 此方法是与Socket关联的回调方法。AcceptAsync操作,并在接受操作完成时调用 + /// + /// + /// + void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e) + { + ProcessAccept(e); + } + private void ProcessAccept(SocketAsyncEventArgs e) + { + try + { + Interlocked.Increment(ref m_clientCount); + //确保监听结束时,有连接才抛给数据接收 + if (e.AcceptSocket.RemoteEndPoint != null) + { + // Get the socket for the accepted client connection and put it into the + //ReadEventArg object user token + SocketAsyncEventArgs readEventArgs = m_Receivepool.Pop(); + //TODO readEventArgs.UserToken这里的 UserToken 有可能是空 + AsyncUserToken userToken; + if (readEventArgs.UserToken == null) + readEventArgs.UserToken = new AsyncUserToken(); + + userToken = (AsyncUserToken)readEventArgs.UserToken; + userToken.Socket = e.AcceptSocket; + userToken.ConnectTime = DateTime.Now; + userToken.Remote = e.AcceptSocket.RemoteEndPoint; + userToken.IPAddress = ((IPEndPoint)(e.AcceptSocket.RemoteEndPoint)).Address; + + + userToken.RevIndex = MaxRevIndexNum; + userToken.SendIndex = MaxSendIndexNum; + + AddUserToken(userToken); + + OnClientNumberChange?.Invoke(1, userToken); + if (!e.AcceptSocket.ReceiveAsync(readEventArgs)) + { + ProcessReceive(readEventArgs); + } + } + } + catch (Exception me) + { + //RuncomLib.Log.LogUtils.Info(me.Message + "\r\n" + me.StackTrace); + } + + // Accept the next connection request + if (e.SocketError == SocketError.OperationAborted) return; + StartAccept(e); + } + #endregion + + #region 收发IOCP循环 + /// 当异步接收操作完成时,会调用此方法。 + /// 如果远程主机关闭了连接,则套接字关闭。 + /// 如果接收到数据,则将数据回显到客户端。 + /// + /// + private void ProcessReceive(SocketAsyncEventArgs e) + { + try + { + // check if the remote host closed the connection + AsyncUserToken token = (AsyncUserToken)e.UserToken; + if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) + { + //读取数据 + //byte[] data = new byte[e.BytesTransferred]; + //Array.Copy(e.Buffer, e.Offset, data, 0, e.BytesTransferred); + //lock (token.Buffer) + lock(token.memoryStream) + { + //token.Buffer.AddRange(data); + token.memoryStream.Write(e.Buffer, e.Offset, e.BytesTransferred); + do + { + + //DataCallBackReady(token, data); + ////从数据池中移除这组数据 + //lock (token.Buffer) + //{ + // token.Buffer.Clear(); + //} + + DataCallBackReady(token, token.memoryStream.ToArray()); + //流复用的方式 不用重新new申请 + token.memoryStream.Position = 0; + token.memoryStream.SetLength(0); + + //这里API处理完后,并没有返回结果,当然结果是要返回的,却不是在这里, 这里的代码只管接收. + //若要返回结果,可在API处理中调用此类对象的SendMessage方法,统一打包发送.不要被微软的示例给迷惑了. + } while (token.memoryStream.Length > 0); + //} while (token.Buffer.Count > 4); + } + + //继续接收. 为什么要这么写,请看Socket.ReceiveAsync方法的说明 + if (!token.Socket.ReceiveAsync(e)) + { + this.ProcessReceive(e); + } + } + else + { + CloseClientSocket(e); + } + } + catch (Exception xe) + { + //RuncomLib.Log.LogUtils.Info(xe.Message + "\r\n" + xe.StackTrace); + } + } + private void ProcessSend(SocketAsyncEventArgs e) + { + if (e.SocketError == SocketError.Success) + { + //TODO + } + else + { + CloseClientSocket(e); + return; + } + ReleaseSocketAsyncEventArgs(e); + SendForMsgPool(); + } + void IO_Completed(object sender, SocketAsyncEventArgs e) + { + // determine which type of operation just completed and call the associated handler + + switch (e.LastOperation) + { + case SocketAsyncOperation.Receive: + ProcessReceive(e); + break; + case SocketAsyncOperation.Send: + ProcessSend(e); + break; + default: + throw new ArgumentException("The last operation completed on the socket was not a receive or send"); + } + } + #endregion + + #region 发送 + int sendrun = 0; + /// + /// 对外暴露的发送消息 + /// + /// + /// 序列化之后的数据 + public void SendToSocket(Socket sk, byte[] data) + { + AsyncUserToken token = GetAsyncUserTokenForSocket(sk); + SendWithIndex(token, data); + } + void SendForMsgPool() + { + //if (flag_SendForMsgPool) return; + try + { + if (sendrun < msg_pool.Count || msg_pool.Count < 1) + return; + + sendrun++; + while (msg_pool.Count > 0) + { + try + { + TokenWithMsg_SourceMode msg = msg_pool.Dequeue(); + //OutNetLog("从信息池取出发送"); + //是心跳包 + if (msg.bHeartbeat) + { + SendHeartbeatMessage(msg.token); + } + else + { + SendMessage(msg.token,msg.data); + } + msg = null; + } + catch + { + OutNetLog("==============================================>"); + } + } + sendrun--; + OutNetLog("!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } + catch (Exception ex) + { + OutNetLog(ex.ToString()); + } + + } + + /// + /// 发送心跳包 + /// + /// + void SendHeartbeatMessage(AsyncUserToken token) + { + if (token == null || token.Socket == null || !token.Socket.Connected) + return; + try + { + if (m_Sendpool.Count > 0) + { + SocketAsyncEventArgs myreadEventArgs = m_Sendpool.Pop(); + myreadEventArgs.UserToken = token; + myreadEventArgs.AcceptSocket = token.Socket; + //直接写入SocketAsyncEventArgs的Buff + HunterNet_Heartbeat.SetDataToSocketAsyncEventArgs(myreadEventArgs); + + //若不需要等待 + if (!token.Socket.SendAsync(myreadEventArgs)) + { + m_Sendpool.Push(myreadEventArgs); + } + return; + } + else + { + //先压入队列,等待m_Sendpool回收 + msg_pool.Enqueue(new TokenWithMsg_SourceMode() { token = token, bHeartbeat = true }); + //OutNetLog("!!!!压入消息发送队列MSG_Pool"); + return; + } + } + catch (Exception e) + { + OutNetLog(e.ToString()); + } + } + + /// + /// 发送数据并计数 + /// + /// + void SendWithIndex(AsyncUserToken token,byte[] data) + { + try + { + //发送数据 + SendMessage(token, data); + token.SendIndex = MaxSendIndexNum; + } + catch + { + CloseReady(token); + } + } + + void SendMessage(AsyncUserToken token, byte[] data) + { + if (token == null || token.Socket == null || !token.Socket.Connected) + return; + try + { + if (m_Sendpool.Count > 0) + { + SocketAsyncEventArgs myreadEventArgs = m_Sendpool.Pop(); + myreadEventArgs.UserToken = token; + myreadEventArgs.AcceptSocket = token.Socket; + myreadEventArgs.SetBuffer(data, 0, data.Length); //将数据放置进去. + + //若不需要等待 + if (!token.Socket.SendAsync(myreadEventArgs)) + { + m_Sendpool.Push(myreadEventArgs); + } + return; + } + else + { + //先压入队列,等待m_Sendpool回收 + msg_pool.Enqueue(new TokenWithMsg_SourceMode() { token = token, data = data ,bHeartbeat = false}); + //OutNetLog("!!!!压入消息发送队列MSG_Pool"); + return; + } + } + catch (Exception e) + { + OutNetLog(e.ToString()); + } + } + #endregion + + #region 处理前预备 + private void DataCallBackReady(AsyncUserToken sk, byte[] data) + { + //增加接收计数 + sk.RevIndex = MaxRevIndexNum; + + try + { + //将数据包交给后台处理,这里你也可以新开个线程来处理.加快速度. + OnReceive?.Invoke(sk, data); + } + catch (Exception ex) + { + OutNetLog("数据解析错误"); + } + } + private void OutNetLog(string msg) + { + OnNetLog?.Invoke(msg); + } + #endregion + + #region 心跳包 + /* + /// + /// 发送心跳包 + /// + /// + /// + private void SendHeartbeatWithIndex(AsyncUserToken token) + { + if (token == null || token.Socket == null || !token.Socket.Connected) + return; + try + { + //OutNetLog(DateTime.Now.ToString() + "发送心跳包"); + token.SendIndex = MaxSendIndexNum; + SendHeartbeatMessage(token); + } + catch (Exception e) + { + CloseReady(token); + } + } + /// + /// 心跳包时钟事件 + /// + /// + /// + private void CheckUpdatetimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + for (int i = 0; i < m_clients.Count(); i++) + { + //接收服务器数据计数 + m_clients[i].RevIndex--; + if (m_clients[i].RevIndex <= 0) + { + //判定掉线 + CloseReady(m_clients[i]); + return; + } + + //发送计数 + m_clients[i].SendIndex--; + if (m_clients[i].SendIndex <= 0)//需要发送心跳包了 + { + //重置倒计时计数 + m_clients[i].SendIndex = MaxSendIndexNum; + SendHeartbeatWithIndex(m_clients[i]); + } + } + } + */ + #endregion + } +} diff --git a/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/SourceMode/TokenMsgPool_SourceMode.cs b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/SourceMode/TokenMsgPool_SourceMode.cs new file mode 100644 index 0000000..32b1504 --- /dev/null +++ b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/SourceMode/TokenMsgPool_SourceMode.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Text; + +namespace HaoYueNet.ServerNetworkNet4x +{ + public class TokenWithMsg_SourceMode + { + public AsyncUserToken token; + public byte[] data; + public bool bHeartbeat; + } + + public class TokenMsgPool_SourceMode + { + //Stack msg_pool; + Queue msg_pool; + + public TokenMsgPool_SourceMode(int capacity) + { + msg_pool = new Queue(capacity); + } + + /// + /// 向 Queue 的末尾添加一个对象。 + /// + /// + public void Enqueue(TokenWithMsg_SourceMode item) + { + lock (msg_pool) + { + msg_pool.Enqueue(item); + } + } + + //移除并返回在 Queue 的开头的对象。 + public TokenWithMsg_SourceMode Dequeue() + { + lock (msg_pool) + { + return msg_pool.Dequeue(); + } + } + + public int Count + { + get { return msg_pool.Count; } + } + + public void Clear() + { + msg_pool.Clear(); + } + } +} diff --git a/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/TcpSaeaServer.cs b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/TcpSaeaServer.cs new file mode 100644 index 0000000..404c176 --- /dev/null +++ b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/TcpSaeaServer.cs @@ -0,0 +1,742 @@ +//using HunterProtobufCore; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using static HaoYueNet.ServerNetworkNet4x.BaseData; + +namespace HaoYueNet.ServerNetworkNet4x +{ + public class TcpSaeaServer + { + #region 定义属性 + protected int MaxRevIndexNum = 50;//响应倒计时计数最大值 + protected int MaxSendIndexNum = 3;//发送倒计时计数最大值 + protected static int TimerInterval = 3000;//计时器间隔 + protected System.Timers.Timer _heartTimer;//心跳包计数器 + public int m_maxConnectNum; //最大连接数 + public int m_revBufferSize; //最大接收字节数 + protected BufferManager m_bufferManager; + protected const int opsToAlloc = 2; + Socket listenSocket; //监听Socket + protected SocketEventPool m_Receivepool; + protected SocketEventPool m_Sendpool; + protected TokenMsgPool msg_pool; + protected int m_clientCount; //连接的客户端数量 + protected Semaphore m_maxNumberAcceptedClients;//信号量 + protected Dictionary _DictSocketAsyncUserToken = new Dictionary(); + List m_clients; //客户端列表 + public List ClientList { private set { m_clients = value; } get { return m_clients; } } //获取客户端列表 + #endregion + + #region 定义委托 + /// + /// 客户端连接数量变化时触发 + /// + /// 当前增加客户的个数(用户退出时为负数,增加时为正数,一般为1) + /// 增加用户的信息 + public delegate void OnClientNumberChangeHandler(int num, AsyncUserToken token); + /// + /// 接收到客户端的数据 + /// + /// 客户端 + /// 客户端数据 + public delegate void OnReceiveDataHandler(AsyncUserToken sk, int CMDID, byte[] data); + /// + /// 断开连接 + /// + /// + public delegate void OnDisconnectHandler(AsyncUserToken sk); + /// + /// 日志 + /// + /// + public delegate void OnNetLogHandler(string msg); + #endregion + + #region 定义事件 + /// + /// 客户端连接数量变化事件 + /// + public event OnClientNumberChangeHandler OnClientNumberChange; + /// + /// 接收到客户端的数据事件 + /// + public event OnReceiveDataHandler OnReceive; + /// + /// 接收到客户端的断开连接 + /// + public event OnDisconnectHandler OnDisconnected; + /// + /// 网络库内部输出 + /// + public event OnNetLogHandler OnNetLog; + #endregion + + /// + /// 构造函数 + /// + /// 最大连接数 + /// 缓存区大小 + public TcpSaeaServer(int numConnections, int receiveBufferSize) + { + m_clientCount = 0; + m_maxConnectNum = numConnections; + m_revBufferSize = receiveBufferSize; + // allocate buffers such that the maximum number of sockets can have one outstanding read and + //write posted to the socket simultaneously + m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToAlloc, receiveBufferSize); + + m_Receivepool = new SocketEventPool(numConnections); + m_Sendpool = new SocketEventPool(numConnections); + + msg_pool = new TokenMsgPool(numConnections); + + m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections); + } + + #region Client操作 + /// + /// 初始化 + /// + public void Init() + { + // Allocates one large byte buffer which all I/O operations use a piece of. This gaurds + // against memory fragmentation + m_bufferManager.InitBuffer(); + m_clients = new List(); + // preallocate pool of SocketAsyncEventArgs objects + SocketAsyncEventArgs readWriteEventArg; + + for (int i = 0; i < m_maxConnectNum; i++) + { + readWriteEventArg = new SocketAsyncEventArgs(); + readWriteEventArg.Completed += new EventHandler(IO_Completed); + readWriteEventArg.UserToken = new AsyncUserToken(); + // assign a byte buffer from the buffer pool to the SocketAsyncEventArg object + m_bufferManager.SetBuffer(readWriteEventArg); + // add SocketAsyncEventArg to the pool + m_Receivepool.Push(readWriteEventArg); + } + + for (int i = 0; i < m_maxConnectNum; i++) + { + readWriteEventArg = new SocketAsyncEventArgs(); + readWriteEventArg.Completed += new EventHandler(IO_Completed); + readWriteEventArg.UserToken = new AsyncUserToken(); + + //发送是否需要如此设置 TODO + m_bufferManager.SetBuffer(readWriteEventArg); + + m_Sendpool.Push(readWriteEventArg); + } + OutNetLog("初始化完毕"); + } + /// + /// 启动服务 + /// + /// + /// 是否端口重用 + /// + public bool Start(IPEndPoint localEndPoint, bool bReuseAddress = false) + { + try + { + ClearUserToken(); + listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + + if (bReuseAddress) + { + listenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + } + + listenSocket.Bind(localEndPoint); + // start the server with a listen backlog of 100 connections + listenSocket.Listen(m_maxConnectNum); + // post accepts on the listening socket + StartAccept(null); + + OutNetLog("监听:" + listenSocket.LocalEndPoint.ToString()); + + _heartTimer = new System.Timers.Timer(); + _heartTimer.Interval = TimerInterval; + _heartTimer.Elapsed += CheckUpdatetimer_Elapsed; + _heartTimer.AutoReset = true; + _heartTimer.Enabled = true; + OutNetLog("开启定时心跳包"); + + return true; + } + catch (Exception) + { + return false; + } + } + /// + /// 停止服务 + /// + public void Stop() + { + foreach (AsyncUserToken token in m_clients) + { + try + { + token.Socket.Shutdown(SocketShutdown.Both); + } + catch (Exception) { } + } + try + { + listenSocket.Shutdown(SocketShutdown.Both); + } + catch (Exception) { } + + listenSocket.Close(); + int c_count = m_clients.Count; + ClearUserToken(); + + if (OnClientNumberChange != null) + OnClientNumberChange(-c_count, null); + } + public void CloseClient(AsyncUserToken token) + { + try {token.Socket.Shutdown(SocketShutdown.Both);} + catch (Exception) { } + } + /// + /// 关闭客户端连接 + /// + /// + void CloseClientSocket(SocketAsyncEventArgs e) + { + AsyncUserToken token = e.UserToken as AsyncUserToken; + CloseReady(token); + // 释放SocketAsyncEventArg,以便其他客户端可以重用它们 + ReleaseSocketAsyncEventArgs(e); + } + void CloseReady(AsyncUserToken token) + { + OnDisconnected?.Invoke(token); + RemoveUserToken(token); + //如果有事件,则调用事件,发送客户端数量变化通知 + OnClientNumberChange?.Invoke(-1, token); + // 关闭与客户端关联的套接字 + try { token.Socket.Shutdown(SocketShutdown.Send); } catch (Exception) { } + token.Socket.Close(); + // 递减计数器以跟踪连接到服务器的客户端总数 + Interlocked.Decrement(ref m_clientCount); + m_maxNumberAcceptedClients.Release(); + } + #endregion + + #region Token管理 + public AsyncUserToken GetAsyncUserTokenForSocket(Socket sk) + { + return _DictSocketAsyncUserToken.ContainsKey(sk) ? _DictSocketAsyncUserToken[sk] : null; + } + void AddUserToken(AsyncUserToken userToken) + { + lock (_DictSocketAsyncUserToken) + { + m_clients.Add(userToken); + _DictSocketAsyncUserToken.Add(userToken.Socket, userToken); + } + } + void RemoveUserToken(AsyncUserToken userToken) + { + lock (_DictSocketAsyncUserToken) + { + m_clients.Remove(userToken); + _DictSocketAsyncUserToken.Remove(userToken.Socket); + } + } + void ClearUserToken() + { + lock (_DictSocketAsyncUserToken) + { + m_clients.Clear(); + _DictSocketAsyncUserToken.Clear(); + } + } + /// + /// 回收SocketAsyncEventArgs + /// + /// + /// + void ReleaseSocketAsyncEventArgs(SocketAsyncEventArgs saea) + { + //saea.UserToken = null;//TODO + //saea.SetBuffer(null, 0, 0); + //saea.Dispose(); + //↑ 这里不要自作主张去清东西,否则回收回去不可用 + + switch (saea.LastOperation) + { + case SocketAsyncOperation.Receive: + m_Receivepool.Push(saea); + break; + case SocketAsyncOperation.Send: + m_Sendpool.Push(saea); + break; + default: + throw new ArgumentException("ReleaseSocketAsyncEventArgs > The last operation completed on the socket was not a receive or send"); + } + + } + #endregion + + #region 监听IOCP循环 + /// + /// 开始接受客户端的连接请求的操作 + /// + /// 在服务器的侦听套接字上发出接受操作时要使用的上下文对象 + public void StartAccept(SocketAsyncEventArgs acceptEventArg) + { + if (acceptEventArg == null) + { + acceptEventArg = new SocketAsyncEventArgs(); + acceptEventArg.Completed += new EventHandler(AcceptEventArg_Completed); + } + else + { + // socket must be cleared since the context object is being reused + acceptEventArg.AcceptSocket = null; + } + + m_maxNumberAcceptedClients.WaitOne(); + if (!listenSocket.AcceptAsync(acceptEventArg)) + { + ProcessAccept(acceptEventArg); + } + } + /// + /// 此方法是与Socket关联的回调方法。AcceptAsync操作,并在接受操作完成时调用 + /// + /// + /// + void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e) + { + ProcessAccept(e); + } + private void ProcessAccept(SocketAsyncEventArgs e) + { + try + { + Interlocked.Increment(ref m_clientCount); + + //确保监听结束时,有连接才抛给数据接收 + if (e.AcceptSocket.RemoteEndPoint != null) + { + // Get the socket for the accepted client connection and put it into the + //ReadEventArg object user token + SocketAsyncEventArgs readEventArgs = m_Receivepool.Pop(); + //TODO readEventArgs.UserToken这里的 UserToken 有可能是空 + AsyncUserToken userToken; + if (readEventArgs.UserToken == null) + readEventArgs.UserToken = new AsyncUserToken(); + + userToken = (AsyncUserToken)readEventArgs.UserToken; + userToken.Socket = e.AcceptSocket; + userToken.ConnectTime = DateTime.Now; + userToken.Remote = e.AcceptSocket.RemoteEndPoint; + userToken.IPAddress = ((IPEndPoint)(e.AcceptSocket.RemoteEndPoint)).Address; + + + userToken.RevIndex = MaxRevIndexNum; + userToken.SendIndex = MaxSendIndexNum; + + AddUserToken(userToken); + + OnClientNumberChange?.Invoke(1, userToken); + if (!e.AcceptSocket.ReceiveAsync(readEventArgs)) + { + ProcessReceive(readEventArgs); + } + } + } + catch (Exception me) + { + //RuncomLib.Log.LogUtils.Info(me.Message + "\r\n" + me.StackTrace); + } + + // Accept the next connection request + if (e.SocketError == SocketError.OperationAborted) return; + StartAccept(e); + } + #endregion + + #region 收发IOCP循环 + /// 当异步接收操作完成时,会调用此方法。 + /// 如果远程主机关闭了连接,则套接字关闭。 + /// 如果接收到数据,则将数据回显到客户端。 + /// + /// + private void ProcessReceive(SocketAsyncEventArgs e) + { + try + { + // check if the remote host closed the connection + AsyncUserToken token = (AsyncUserToken)e.UserToken; + if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) + { + //读取数据 + //byte[] data = new byte[e.BytesTransferred]; + //Array.Copy(e.Buffer, e.Offset, data, 0, e.BytesTransferred); + //lock (token.Buffer) + lock(token.memoryStream) + { + //token.Buffer.AddRange(data); + token.memoryStream.Write(e.Buffer, e.Offset, e.BytesTransferred); + do + { + //如果包头不完整 + //if (token.Buffer.Count < 4) + if (token.memoryStream.Length < 4) + break; + + ////判断包的长度 + //byte[] lenBytes = token.Buffer.GetRange(0, 4).ToArray(); + //int packageLen = BitConverter.ToInt32(lenBytes, 0) - 4; + //if (packageLen > token.Buffer.Count - 4) + //{ //长度不够时,退出循环,让程序继续接收 + // break; + //} + + long FristBeginPos = token.memoryStream.Position; + byte[] lenBytes = new byte[4]; + token.memoryStream.Seek(0, SeekOrigin.Begin); + token.memoryStream.Read(lenBytes, 0, 4); + int packageLen = BitConverter.ToInt32(lenBytes, 0) - 4; + if (packageLen > token.memoryStream.Length - 4) + { + token.memoryStream.Seek(FristBeginPos, SeekOrigin.Begin); + //长度不够时,退出循环,让程序继续接收 + break; + } + + ////包够长时,则提取出来,交给后面的程序去处理 + //byte[] rev = token.Buffer.GetRange(4, packageLen).ToArray(); + + byte[] rev = new byte[packageLen]; + token.memoryStream.Seek(4, SeekOrigin.Begin); + token.memoryStream.Read(rev, 0, packageLen); + + //从数据池中移除这组数据 + //lock (token.Buffer) + //{ + // token.Buffer.RemoveRange(0, packageLen + 4); + //} + + token.memoryStream.Seek(FristBeginPos, SeekOrigin.Begin); + //从数据池中移除这组数据 + lock (token.memoryStream) + { + //token.memoryStream.Position = 0; + //token.memoryStream.SetLength(0); + int numberOfBytesToRemove = packageLen + 4; + byte[] buf = token.memoryStream.GetBuffer(); + Buffer.BlockCopy(buf, numberOfBytesToRemove, buf, 0, (int)token.memoryStream.Length - numberOfBytesToRemove); + token.memoryStream.SetLength(token.memoryStream.Length - numberOfBytesToRemove); + } + + DataCallBackReady(token, rev); + + //这里API处理完后,并没有返回结果,当然结果是要返回的,却不是在这里, 这里的代码只管接收. + //若要返回结果,可在API处理中调用此类对象的SendMessage方法,统一打包发送.不要被微软的示例给迷惑了. + //} while (token.Buffer.Count > 4); + } while (token.memoryStream.Length > 4); + } + + //继续接收. 为什么要这么写,请看Socket.ReceiveAsync方法的说明 + if (!token.Socket.ReceiveAsync(e)) + { + this.ProcessReceive(e); + } + } + else + { + CloseClientSocket(e); + } + } + catch (Exception xe) + { + //RuncomLib.Log.LogUtils.Info(xe.Message + "\r\n" + xe.StackTrace); + } + } + private void ProcessSend(SocketAsyncEventArgs e) + { + if (e.SocketError == SocketError.Success) + { + //TODO + } + else + { + CloseClientSocket(e); + return; + } + ReleaseSocketAsyncEventArgs(e); + SendForMsgPool(); + } + void IO_Completed(object sender, SocketAsyncEventArgs e) + { + // determine which type of operation just completed and call the associated handler + + switch (e.LastOperation) + { + case SocketAsyncOperation.Receive: + ProcessReceive(e); + break; + case SocketAsyncOperation.Send: + ProcessSend(e); + break; + default: + throw new ArgumentException("The last operation completed on the socket was not a receive or send"); + } + } + #endregion + + #region 发送 + int sendrun = 0; + /// + /// 对外暴露的发送消息 + /// + /// + /// 序列化之后的数据 + public void SendToSocket(Socket sk, int CMDID, int ERRCODE, byte[] data) + { + AsyncUserToken token = GetAsyncUserTokenForSocket(sk); + /*HunterNet_S2C _s2cdata = new HunterNet_S2C(); + _s2cdata.HunterNetCoreCmdID = CMDID; + _s2cdata.HunterNetCoreData = ByteString.CopyFrom(data); + _s2cdata.HunterNetCoreERRORCode = ERRCODE; + byte[] _finaldata = Serizlize(_s2cdata);*/ + + //byte[] _finaldata = HunterNet_S2C.CreatePkgData((ushort)CMDID, (ushort)ERRCODE, data); + + SendWithIndex(token, (ushort)CMDID, (ushort)ERRCODE, data); + } + void SendForMsgPool() + { + //if (flag_SendForMsgPool) return; + try + { + if (sendrun < msg_pool.Count || msg_pool.Count < 1) + return; + + sendrun++; + while (msg_pool.Count > 0) + { + try + { + TokenWithMsg msg = msg_pool.Dequeue(); + //OutNetLog("从信息池取出发送"); + //是心跳包 + if (msg.bHeartbeat) + { + SendHeartbeatMessage(msg.token); + } + else + { + SendMessage(msg.token, msg.CMDID, msg.Error, msg.data); + } + msg = null; + } + catch + { + OutNetLog("==============================================>"); + } + } + sendrun--; + OutNetLog("!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } + catch (Exception ex) + { + OutNetLog(ex.ToString()); + } + + } + + /// + /// 发送心跳包 + /// + /// + void SendHeartbeatMessage(AsyncUserToken token) + { + if (token == null || token.Socket == null || !token.Socket.Connected) + return; + try + { + if (m_Sendpool.Count > 0) + { + SocketAsyncEventArgs myreadEventArgs = m_Sendpool.Pop(); + myreadEventArgs.UserToken = token; + myreadEventArgs.AcceptSocket = token.Socket; + //直接写入SocketAsyncEventArgs的Buff + HunterNet_Heartbeat.SetDataToSocketAsyncEventArgs(myreadEventArgs); + + //若不需要等待 + if (!token.Socket.SendAsync(myreadEventArgs)) + { + m_Sendpool.Push(myreadEventArgs); + } + return; + } + else + { + //先压入队列,等待m_Sendpool回收 + msg_pool.Enqueue(new TokenWithMsg() { token = token, bHeartbeat = true }); + //OutNetLog("!!!!压入消息发送队列MSG_Pool"); + return; + } + } + catch (Exception e) + { + OutNetLog(e.ToString()); + } + } + + /// + /// 发送数据并计数 + /// + /// + void SendWithIndex(AsyncUserToken token, UInt16 CmdID, UInt16 ERRCODE, byte[] data) + { + try + { + //发送数据 + SendMessage(token, CmdID, ERRCODE, data); + token.SendIndex = MaxSendIndexNum; + } + catch + { + CloseReady(token); + } + } + + void SendMessage(AsyncUserToken token, UInt16 CmdID, UInt16 Error, byte[] data) + { + if (token == null || token.Socket == null || !token.Socket.Connected) + return; + try + { + if (m_Sendpool.Count > 0) + { + SocketAsyncEventArgs myreadEventArgs = m_Sendpool.Pop(); + myreadEventArgs.UserToken = token; + myreadEventArgs.AcceptSocket = token.Socket; + //myreadEventArgs.SetBuffer(message, 0, message.Length); //将数据放置进去. + //更换为CMDID和Data直接写入SocketAsyncEventArgs的Buff + HunterNet_S2C.SetDataToSocketAsyncEventArgs(myreadEventArgs, CmdID, Error, data); + + //若不需要等待 + if (!token.Socket.SendAsync(myreadEventArgs)) + { + m_Sendpool.Push(myreadEventArgs); + } + return; + } + else + { + //先压入队列,等待m_Sendpool回收 + msg_pool.Enqueue(new TokenWithMsg() { token = token, CMDID = CmdID, Error = Error, data = data }); + //OutNetLog("!!!!压入消息发送队列MSG_Pool"); + return; + } + } + catch (Exception e) + { + OutNetLog(e.ToString()); + } + } + #endregion + + #region 处理前预备 + private void DataCallBackReady(AsyncUserToken sk, byte[] data) + { + //增加接收计数 + sk.RevIndex = MaxRevIndexNum; + + if (data.Length == 1 && data[0] == 0x00)//心跳包 + { + //OutNetLog("收到心跳包"); + //无处理 + } + else + { + try + { + //将数据包交给后台处理,这里你也可以新开个线程来处理.加快速度. + /* + HunterNet_C2S _s2c = DeSerizlize(data); + OnReceive?.Invoke(sk, (int)_s2c.HunterNetCoreCmdID, _s2c.HunterNetCoreData.ToArray()); + //DataCallBack(sk, (int)_s2c.HunterNetCoreCmdID, _s2c.HunterNetCoreData.ToArray()); + */ + HunterNet_C2S.AnalysisPkgData(data, out ushort CmdID, out byte[] resultdata); + OnReceive?.Invoke(sk, CmdID, resultdata); + } + catch (Exception ex) + { + OutNetLog("数据解析错误"); + } + } + } + private void OutNetLog(string msg) + { + OnNetLog?.Invoke(msg); + } + #endregion + + #region 心跳包 + /// + /// 发送心跳包 + /// + /// + /// + private void SendHeartbeatWithIndex(AsyncUserToken token) + { + if (token == null || token.Socket == null || !token.Socket.Connected) + return; + try + { + //OutNetLog(DateTime.Now.ToString() + "发送心跳包"); + token.SendIndex = MaxSendIndexNum; + SendHeartbeatMessage(token); + } + catch (Exception e) + { + CloseReady(token); + } + } + /// + /// 心跳包时钟事件 + /// + /// + /// + private void CheckUpdatetimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + for (int i = 0; i < m_clients.Count; i++) + { + //接收服务器数据计数 + m_clients[i].RevIndex--; + if (m_clients[i].RevIndex <= 0) + { + //判定掉线 + CloseReady(m_clients[i]); + return; + } + + //发送计数 + m_clients[i].SendIndex--; + if (m_clients[i].SendIndex <= 0)//需要发送心跳包了 + { + //重置倒计时计数 + m_clients[i].SendIndex = MaxSendIndexNum; + SendHeartbeatWithIndex(m_clients[i]); + } + } + } + #endregion + } +} \ No newline at end of file diff --git a/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/TokenMsgPool.cs b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/TokenMsgPool.cs new file mode 100644 index 0000000..bc3c27e --- /dev/null +++ b/NetLib/HaoYueNet.ServerNetworkNet4x/NetWork/TokenMsgPool.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Text; + +namespace HaoYueNet.ServerNetworkNet4x +{ + public class TokenWithMsg + { + public AsyncUserToken token; + public UInt16 CMDID; + public UInt16 Error; + public byte[] data; + public bool bHeartbeat; + } + + public class TokenMsgPool + { + //Stack msg_pool; + Queue msg_pool; + + public TokenMsgPool(int capacity) + { + msg_pool = new Queue(capacity); + } + + /// + /// 向 Queue 的末尾添加一个对象。 + /// + /// + public void Enqueue(TokenWithMsg item) + { + lock (msg_pool) + { + msg_pool.Enqueue(item); + } + } + + //移除并返回在 Queue 的开头的对象。 + public TokenWithMsg Dequeue() + { + lock (msg_pool) + { + return msg_pool.Dequeue(); + } + } + + public int Count + { + get { return msg_pool.Count; } + } + + public void Clear() + { + msg_pool.Clear(); + } + } + + /* + public class TokenWithMsg + { + public AsyncUserToken token; + public byte[] message; + } + + public class TokenMsgPool + { + //Stack msg_pool; + Queue msg_pool; + + public TokenMsgPool(int capacity) + { + //msg_pool = new Stack(capacity); + msg_pool = new Queue(capacity); + } + + //public void Push(TokenWithMsg item) + //{ + // if (item == null) { throw new ArgumentNullException("Items added to a SocketAsyncEventArgsPool cannot be null"); } + // lock (msg_pool) + // { + // msg_pool.Push(item); + // } + //} + + /// + /// 向 Queue 的末尾添加一个对象。 + /// + /// + public void Enqueue(TokenWithMsg item) + { + lock (msg_pool) + { + msg_pool.Enqueue(item); + } + } + + //移除并返回在 Queue 的开头的对象。 + public TokenWithMsg Dequeue() + { + lock (msg_pool) + { + return msg_pool.Dequeue(); + } + } + + //// Removes a SocketAsyncEventArgs instance from the pool + //// and returns the object removed from the pool + //public TokenWithMsg Pop() + //{ + // lock (msg_pool) + // { + // return msg_pool.Pop(); + // } + //} + + // The number of SocketAsyncEventArgs instances in the pool + public int Count + { + get { return msg_pool.Count; } + } + + public void Clear() + { + msg_pool.Clear(); + } + } + */ +} diff --git a/NetLib/HaoYueNet.ServerNetworkNet4x/Properties/AssemblyInfo.cs b/NetLib/HaoYueNet.ServerNetworkNet4x/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..07c9c80 --- /dev/null +++ b/NetLib/HaoYueNet.ServerNetworkNet4x/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("HaoYueNet.ServerNetworkNet4xNet4X")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("HaoYueNet.ServerNetworkNet4xNet4X")] +[assembly: AssemblyCopyright("Copyright © 2024")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("036f9bd9-308c-4194-ab40-c5952ef0e9f5")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/NetLib/HaoYueNet.ServerNetworkNet4x/ProtobufHunterNetCore.cs b/NetLib/HaoYueNet.ServerNetworkNet4x/ProtobufHunterNetCore.cs new file mode 100644 index 0000000..b2904aa --- /dev/null +++ b/NetLib/HaoYueNet.ServerNetworkNet4x/ProtobufHunterNetCore.cs @@ -0,0 +1,506 @@ +//// +//// Generated by the protocol buffer compiler. DO NOT EDIT! +//// source: protobuf_HunterNetCore.proto +//// +//#pragma warning disable 1591, 0612, 3021 +//#region Designer generated code + +//using pb = global::Google.Protobuf; +//using pbc = global::Google.Protobuf.Collections; +//using pbr = global::Google.Protobuf.Reflection; +//using scg = global::System.Collections.Generic; +//namespace HunterProtobufCore { + +// /// Holder for reflection information generated from protobuf_HunterNetCore.proto +// public static partial class ProtobufHunterNetCoreReflection { + +// #region Descriptor +// /// File descriptor for protobuf_HunterNetCore.proto +// public static pbr::FileDescriptor Descriptor { +// get { return descriptor; } +// } +// private static pbr::FileDescriptor descriptor; + +// static ProtobufHunterNetCoreReflection() { +// byte[] descriptorData = global::System.Convert.FromBase64String( +// string.Concat( +// "Chxwcm90b2J1Zl9IdW50ZXJOZXRDb3JlLnByb3RvEhJIdW50ZXJQcm90b2J1", +// "ZkNvcmUiSAoNSHVudGVyTmV0X0MyUxIbChNIdW50ZXJOZXRDb3JlX0NtZElE", +// "GAEgASgFEhoKEkh1bnRlck5ldENvcmVfRGF0YRgCIAEoDCJpCg1IdW50ZXJO", +// "ZXRfUzJDEhsKE0h1bnRlck5ldENvcmVfQ21kSUQYASABKAUSHwoXSHVudGVy", +// "TmV0Q29yZV9FUlJPUkNvZGUYAiABKAUSGgoSSHVudGVyTmV0Q29yZV9EYXRh", +// "GAMgASgMQgJIAWIGcHJvdG8z")); +// descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, +// new pbr::FileDescriptor[] { }, +// new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { +// new pbr::GeneratedClrTypeInfo(typeof(global::HunterProtobufCore.HunterNet_C2S), global::HunterProtobufCore.HunterNet_C2S.Parser, new[]{ "HunterNetCoreCmdID", "HunterNetCoreData" }, null, null, null, null), +// new pbr::GeneratedClrTypeInfo(typeof(global::HunterProtobufCore.HunterNet_S2C), global::HunterProtobufCore.HunterNet_S2C.Parser, new[]{ "HunterNetCoreCmdID", "HunterNetCoreERRORCode", "HunterNetCoreData" }, null, null, null, null) +// })); +// } +// #endregion + +// } +// #region Messages +// /// +// ///上行 +// /// +// public sealed partial class HunterNet_C2S : pb::IMessage +// #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +// , pb::IBufferMessage +// #endif +// { +// private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HunterNet_C2S()); +// private pb::UnknownFieldSet _unknownFields; +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public static pb::MessageParser Parser { get { return _parser; } } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public static pbr::MessageDescriptor Descriptor { +// get { return global::HunterProtobufCore.ProtobufHunterNetCoreReflection.Descriptor.MessageTypes[0]; } +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// pbr::MessageDescriptor pb::IMessage.Descriptor { +// get { return Descriptor; } +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public HunterNet_C2S() { +// OnConstruction(); +// } + +// partial void OnConstruction(); + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public HunterNet_C2S(HunterNet_C2S other) : this() { +// hunterNetCoreCmdID_ = other.hunterNetCoreCmdID_; +// hunterNetCoreData_ = other.hunterNetCoreData_; +// _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public HunterNet_C2S Clone() { +// return new HunterNet_C2S(this); +// } + +// /// Field number for the "HunterNetCore_CmdID" field. +// public const int HunterNetCoreCmdIDFieldNumber = 1; +// private int hunterNetCoreCmdID_; +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public int HunterNetCoreCmdID { +// get { return hunterNetCoreCmdID_; } +// set { +// hunterNetCoreCmdID_ = value; +// } +// } + +// /// Field number for the "HunterNetCore_Data" field. +// public const int HunterNetCoreDataFieldNumber = 2; +// private pb::ByteString hunterNetCoreData_ = pb::ByteString.Empty; +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public pb::ByteString HunterNetCoreData { +// get { return hunterNetCoreData_; } +// set { +// hunterNetCoreData_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); +// } +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public override bool Equals(object other) { +// return Equals(other as HunterNet_C2S); +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public bool Equals(HunterNet_C2S other) { +// if (ReferenceEquals(other, null)) { +// return false; +// } +// if (ReferenceEquals(other, this)) { +// return true; +// } +// if (HunterNetCoreCmdID != other.HunterNetCoreCmdID) return false; +// if (HunterNetCoreData != other.HunterNetCoreData) return false; +// return Equals(_unknownFields, other._unknownFields); +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public override int GetHashCode() { +// int hash = 1; +// if (HunterNetCoreCmdID != 0) hash ^= HunterNetCoreCmdID.GetHashCode(); +// if (HunterNetCoreData.Length != 0) hash ^= HunterNetCoreData.GetHashCode(); +// if (_unknownFields != null) { +// hash ^= _unknownFields.GetHashCode(); +// } +// return hash; +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public override string ToString() { +// return pb::JsonFormatter.ToDiagnosticString(this); +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public void WriteTo(pb::CodedOutputStream output) { +// #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +// output.WriteRawMessage(this); +// #else +// if (HunterNetCoreCmdID != 0) { +// output.WriteRawTag(8); +// output.WriteInt32(HunterNetCoreCmdID); +// } +// if (HunterNetCoreData.Length != 0) { +// output.WriteRawTag(18); +// output.WriteBytes(HunterNetCoreData); +// } +// if (_unknownFields != null) { +// _unknownFields.WriteTo(output); +// } +// #endif +// } + +// #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { +// if (HunterNetCoreCmdID != 0) { +// output.WriteRawTag(8); +// output.WriteInt32(HunterNetCoreCmdID); +// } +// if (HunterNetCoreData.Length != 0) { +// output.WriteRawTag(18); +// output.WriteBytes(HunterNetCoreData); +// } +// if (_unknownFields != null) { +// _unknownFields.WriteTo(ref output); +// } +// } +// #endif + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public int CalculateSize() { +// int size = 0; +// if (HunterNetCoreCmdID != 0) { +// size += 1 + pb::CodedOutputStream.ComputeInt32Size(HunterNetCoreCmdID); +// } +// if (HunterNetCoreData.Length != 0) { +// size += 1 + pb::CodedOutputStream.ComputeBytesSize(HunterNetCoreData); +// } +// if (_unknownFields != null) { +// size += _unknownFields.CalculateSize(); +// } +// return size; +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public void MergeFrom(HunterNet_C2S other) { +// if (other == null) { +// return; +// } +// if (other.HunterNetCoreCmdID != 0) { +// HunterNetCoreCmdID = other.HunterNetCoreCmdID; +// } +// if (other.HunterNetCoreData.Length != 0) { +// HunterNetCoreData = other.HunterNetCoreData; +// } +// _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public void MergeFrom(pb::CodedInputStream input) { +// #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +// input.ReadRawMessage(this); +// #else +// uint tag; +// while ((tag = input.ReadTag()) != 0) { +// switch(tag) { +// default: +// _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); +// break; +// case 8: { +// HunterNetCoreCmdID = input.ReadInt32(); +// break; +// } +// case 18: { +// HunterNetCoreData = input.ReadBytes(); +// break; +// } +// } +// } +// #endif +// } + +// #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { +// uint tag; +// while ((tag = input.ReadTag()) != 0) { +// switch(tag) { +// default: +// _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); +// break; +// case 8: { +// HunterNetCoreCmdID = input.ReadInt32(); +// break; +// } +// case 18: { +// HunterNetCoreData = input.ReadBytes(); +// break; +// } +// } +// } +// } +// #endif + +// } + +// /// +// ///下行 +// /// +// public sealed partial class HunterNet_S2C : pb::IMessage +// #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +// , pb::IBufferMessage +// #endif +// { +// private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HunterNet_S2C()); +// private pb::UnknownFieldSet _unknownFields; +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public static pb::MessageParser Parser { get { return _parser; } } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public static pbr::MessageDescriptor Descriptor { +// get { return global::HunterProtobufCore.ProtobufHunterNetCoreReflection.Descriptor.MessageTypes[1]; } +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// pbr::MessageDescriptor pb::IMessage.Descriptor { +// get { return Descriptor; } +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public HunterNet_S2C() { +// OnConstruction(); +// } + +// partial void OnConstruction(); + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public HunterNet_S2C(HunterNet_S2C other) : this() { +// hunterNetCoreCmdID_ = other.hunterNetCoreCmdID_; +// hunterNetCoreERRORCode_ = other.hunterNetCoreERRORCode_; +// hunterNetCoreData_ = other.hunterNetCoreData_; +// _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public HunterNet_S2C Clone() { +// return new HunterNet_S2C(this); +// } + +// /// Field number for the "HunterNetCore_CmdID" field. +// public const int HunterNetCoreCmdIDFieldNumber = 1; +// private int hunterNetCoreCmdID_; +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public int HunterNetCoreCmdID { +// get { return hunterNetCoreCmdID_; } +// set { +// hunterNetCoreCmdID_ = value; +// } +// } + +// /// Field number for the "HunterNetCore_ERRORCode" field. +// public const int HunterNetCoreERRORCodeFieldNumber = 2; +// private int hunterNetCoreERRORCode_; +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public int HunterNetCoreERRORCode { +// get { return hunterNetCoreERRORCode_; } +// set { +// hunterNetCoreERRORCode_ = value; +// } +// } + +// /// Field number for the "HunterNetCore_Data" field. +// public const int HunterNetCoreDataFieldNumber = 3; +// private pb::ByteString hunterNetCoreData_ = pb::ByteString.Empty; +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public pb::ByteString HunterNetCoreData { +// get { return hunterNetCoreData_; } +// set { +// hunterNetCoreData_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); +// } +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public override bool Equals(object other) { +// return Equals(other as HunterNet_S2C); +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public bool Equals(HunterNet_S2C other) { +// if (ReferenceEquals(other, null)) { +// return false; +// } +// if (ReferenceEquals(other, this)) { +// return true; +// } +// if (HunterNetCoreCmdID != other.HunterNetCoreCmdID) return false; +// if (HunterNetCoreERRORCode != other.HunterNetCoreERRORCode) return false; +// if (HunterNetCoreData != other.HunterNetCoreData) return false; +// return Equals(_unknownFields, other._unknownFields); +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public override int GetHashCode() { +// int hash = 1; +// if (HunterNetCoreCmdID != 0) hash ^= HunterNetCoreCmdID.GetHashCode(); +// if (HunterNetCoreERRORCode != 0) hash ^= HunterNetCoreERRORCode.GetHashCode(); +// if (HunterNetCoreData.Length != 0) hash ^= HunterNetCoreData.GetHashCode(); +// if (_unknownFields != null) { +// hash ^= _unknownFields.GetHashCode(); +// } +// return hash; +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public override string ToString() { +// return pb::JsonFormatter.ToDiagnosticString(this); +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public void WriteTo(pb::CodedOutputStream output) { +// #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +// output.WriteRawMessage(this); +// #else +// if (HunterNetCoreCmdID != 0) { +// output.WriteRawTag(8); +// output.WriteInt32(HunterNetCoreCmdID); +// } +// if (HunterNetCoreERRORCode != 0) { +// output.WriteRawTag(16); +// output.WriteInt32(HunterNetCoreERRORCode); +// } +// if (HunterNetCoreData.Length != 0) { +// output.WriteRawTag(26); +// output.WriteBytes(HunterNetCoreData); +// } +// if (_unknownFields != null) { +// _unknownFields.WriteTo(output); +// } +// #endif +// } + +// #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { +// if (HunterNetCoreCmdID != 0) { +// output.WriteRawTag(8); +// output.WriteInt32(HunterNetCoreCmdID); +// } +// if (HunterNetCoreERRORCode != 0) { +// output.WriteRawTag(16); +// output.WriteInt32(HunterNetCoreERRORCode); +// } +// if (HunterNetCoreData.Length != 0) { +// output.WriteRawTag(26); +// output.WriteBytes(HunterNetCoreData); +// } +// if (_unknownFields != null) { +// _unknownFields.WriteTo(ref output); +// } +// } +// #endif + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public int CalculateSize() { +// int size = 0; +// if (HunterNetCoreCmdID != 0) { +// size += 1 + pb::CodedOutputStream.ComputeInt32Size(HunterNetCoreCmdID); +// } +// if (HunterNetCoreERRORCode != 0) { +// size += 1 + pb::CodedOutputStream.ComputeInt32Size(HunterNetCoreERRORCode); +// } +// if (HunterNetCoreData.Length != 0) { +// size += 1 + pb::CodedOutputStream.ComputeBytesSize(HunterNetCoreData); +// } +// if (_unknownFields != null) { +// size += _unknownFields.CalculateSize(); +// } +// return size; +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public void MergeFrom(HunterNet_S2C other) { +// if (other == null) { +// return; +// } +// if (other.HunterNetCoreCmdID != 0) { +// HunterNetCoreCmdID = other.HunterNetCoreCmdID; +// } +// if (other.HunterNetCoreERRORCode != 0) { +// HunterNetCoreERRORCode = other.HunterNetCoreERRORCode; +// } +// if (other.HunterNetCoreData.Length != 0) { +// HunterNetCoreData = other.HunterNetCoreData; +// } +// _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); +// } + +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// public void MergeFrom(pb::CodedInputStream input) { +// #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +// input.ReadRawMessage(this); +// #else +// uint tag; +// while ((tag = input.ReadTag()) != 0) { +// switch(tag) { +// default: +// _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); +// break; +// case 8: { +// HunterNetCoreCmdID = input.ReadInt32(); +// break; +// } +// case 16: { +// HunterNetCoreERRORCode = input.ReadInt32(); +// break; +// } +// case 26: { +// HunterNetCoreData = input.ReadBytes(); +// break; +// } +// } +// } +// #endif +// } + +// #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] +// void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { +// uint tag; +// while ((tag = input.ReadTag()) != 0) { +// switch(tag) { +// default: +// _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); +// break; +// case 8: { +// HunterNetCoreCmdID = input.ReadInt32(); +// break; +// } +// case 16: { +// HunterNetCoreERRORCode = input.ReadInt32(); +// break; +// } +// case 26: { +// HunterNetCoreData = input.ReadBytes(); +// break; +// } +// } +// } +// } +// #endif + +// } + +// #endregion + +//} + +//#endregion Designer generated code