[增加]1. 增加网络组件
This commit is contained in:
parent
2c9e2d4d42
commit
0e536bee95
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cce90d3706293ec4a8c26bb8419c1a46
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "GameFrameX.Network.Editor",
|
||||
"references": [
|
||||
"GameFrameX.Network.Runtime",
|
||||
"GameFrameX.Editor",
|
||||
"GameFrameX.Runtime"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1bf417993ca661a44b4e2c55c4908e7b
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 27dca38c9a841974b9c07cddf1e4a1f0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,71 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using GameFrameX.Editor;
|
||||
using GameFrameX.Network.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameFrameX.Network.Editor
|
||||
{
|
||||
[CustomEditor(typeof(NetworkComponent))]
|
||||
internal sealed class NetworkComponentInspector : GameFrameworkInspector
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
if (!EditorApplication.isPlaying)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Available during runtime only.", MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
NetworkComponent t = (NetworkComponent)target;
|
||||
|
||||
if (IsPrefabInHierarchy(t.gameObject))
|
||||
{
|
||||
EditorGUILayout.LabelField("Network Channel Count", t.NetworkChannelCount.ToString());
|
||||
|
||||
INetworkChannel[] networkChannels = t.GetAllNetworkChannels();
|
||||
foreach (INetworkChannel networkChannel in networkChannels)
|
||||
{
|
||||
DrawNetworkChannel(networkChannel);
|
||||
}
|
||||
}
|
||||
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void DrawNetworkChannel(INetworkChannel networkChannel)
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
{
|
||||
EditorGUILayout.LabelField(networkChannel.Name, networkChannel.Connected ? "Connected" : "Disconnected");
|
||||
// EditorGUILayout.LabelField("Service Type", networkChannel.ServiceType.ToString());
|
||||
EditorGUILayout.LabelField("Address Family", networkChannel.AddressFamily.ToString());
|
||||
EditorGUILayout.LabelField("Local Address", networkChannel.Connected ? networkChannel.Socket.LocalEndPoint.ToString() : "Unavailable");
|
||||
EditorGUILayout.LabelField("Remote Address", networkChannel.Connected ? networkChannel.Socket.RemoteEndPoint.ToString() : "Unavailable");
|
||||
EditorGUILayout.LabelField("Send Packet", Utility.Text.Format("{0} / {1}", networkChannel.SendPacketCount, networkChannel.SentPacketCount));
|
||||
EditorGUILayout.LabelField("Receive Packet", Utility.Text.Format("{0} / {1}", networkChannel.ReceivePacketCount, networkChannel.ReceivedPacketCount));
|
||||
EditorGUILayout.LabelField("Miss Heart Beat Count", networkChannel.MissHeartBeatCount.ToString());
|
||||
EditorGUILayout.LabelField("Heart Beat", Utility.Text.Format("{0:F2} / {1:F2}", networkChannel.HeartBeatElapseSeconds, networkChannel.HeartBeatInterval));
|
||||
EditorGUI.BeginDisabledGroup(!networkChannel.Connected);
|
||||
{
|
||||
if (GUILayout.Button("Disconnect"))
|
||||
{
|
||||
networkChannel.Close();
|
||||
}
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7cbb7330261939244ac0b87d6798313a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [2023] [ALianBlank of copyright owner][alianblank@outlook.com][https://alianblank.com/]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 572d9c8c818718f47a23fb9689821082
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
20
README.md
20
README.md
|
@ -1 +1,19 @@
|
|||
# com.alianblank.gameframex.unity.network
|
||||
## HOMEPAGE
|
||||
|
||||
GameFrameX 的 Network 长连接网络组件
|
||||
|
||||
**Network 长连接网络组件 (Network Component)** - 提供长连接网络组件相关的接口。
|
||||
|
||||
# 使用文档(文档编写于GPT4)
|
||||
|
||||
## 注意事项
|
||||
|
||||
# 使用方式(任选其一)
|
||||
|
||||
1. 直接在 `manifest.json` 的文件中的 `dependencies` 节点下添加以下内容
|
||||
```json
|
||||
{"com.alianblank.gameframex.network": "https://github.com/AlianBlank/com.alianblank.gameframex.unity.network.git"}
|
||||
```
|
||||
2. 在Unity 的`Packages Manager` 中使用`Git URL` 的方式添加库,地址为:https://github.com/AlianBlank/com.alianblank.gameframex.unity.network.git
|
||||
|
||||
3. 直接下载仓库放置到Unity 项目的`Packages` 目录下。会自动加载识别
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b4c88c16e8f340f43b01d901b61d9fd0
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: acbd2340e68851d47a849bfa6a19ff6a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 689f25156dd5479bbc9e048eed1f05c3
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,63 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using GameFrameX.Event.Runtime;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络连接关闭事件。
|
||||
/// </summary>
|
||||
public sealed class NetworkClosedEventArgs : GameEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络连接关闭事件编号。
|
||||
/// </summary>
|
||||
public static readonly string EventId = typeof(NetworkClosedEventArgs).FullName;
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络连接关闭事件编号。
|
||||
/// </summary>
|
||||
public override string Id
|
||||
{
|
||||
get { return EventId; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络连接关闭事件的新实例。
|
||||
/// </summary>
|
||||
public NetworkClosedEventArgs()
|
||||
{
|
||||
NetworkChannel = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道。
|
||||
/// </summary>
|
||||
public INetworkChannel NetworkChannel { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建网络连接关闭事件。
|
||||
/// </summary>
|
||||
/// <param name="networkChannel">网络频道。</param>
|
||||
/// <returns>创建的网络连接关闭事件。</returns>
|
||||
public static NetworkClosedEventArgs Create(INetworkChannel networkChannel)
|
||||
{
|
||||
NetworkClosedEventArgs networkClosedEventArgs = ReferencePool.Acquire<NetworkClosedEventArgs>();
|
||||
networkClosedEventArgs.NetworkChannel = networkChannel;
|
||||
return networkClosedEventArgs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理网络连接关闭事件。
|
||||
/// </summary>
|
||||
public override void Clear()
|
||||
{
|
||||
NetworkChannel = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 73bf0753fd824f3c9b5a519141eac1e7
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,72 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using GameFrameX.Event.Runtime;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络连接成功事件。
|
||||
/// </summary>
|
||||
public sealed class NetworkConnectedEventArgs : GameEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络连接成功事件编号。
|
||||
/// </summary>
|
||||
public static readonly string EventId = typeof(NetworkConnectedEventArgs).FullName;
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络连接成功事件编号。
|
||||
/// </summary>
|
||||
public override string Id
|
||||
{
|
||||
get { return EventId; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络连接成功事件的新实例。
|
||||
/// </summary>
|
||||
public NetworkConnectedEventArgs()
|
||||
{
|
||||
NetworkChannel = null;
|
||||
UserData = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道。
|
||||
/// </summary>
|
||||
public INetworkChannel NetworkChannel { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户自定义数据。
|
||||
/// </summary>
|
||||
public object UserData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建网络连接成功事件。
|
||||
/// </summary>
|
||||
/// <param name="networkChannel">网络频道。</param>
|
||||
/// <param name="userData">用户自定义数据。</param>
|
||||
/// <returns>创建的网络连接成功事件。</returns>
|
||||
public static NetworkConnectedEventArgs Create(INetworkChannel networkChannel, object userData)
|
||||
{
|
||||
NetworkConnectedEventArgs networkConnectedEventArgs = ReferencePool.Acquire<NetworkConnectedEventArgs>();
|
||||
networkConnectedEventArgs.NetworkChannel = networkChannel;
|
||||
networkConnectedEventArgs.UserData = userData;
|
||||
return networkConnectedEventArgs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理网络连接成功事件。
|
||||
/// </summary>
|
||||
public override void Clear()
|
||||
{
|
||||
NetworkChannel = null;
|
||||
UserData = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 624ae69be674436a963446040fc8332d
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,72 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using GameFrameX.Event.Runtime;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户自定义网络错误事件。
|
||||
/// </summary>
|
||||
public sealed class NetworkCustomErrorEventArgs : GameEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户自定义网络错误事件编号。
|
||||
/// </summary>
|
||||
public static readonly string EventId = typeof(NetworkCustomErrorEventArgs).FullName;
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户自定义网络错误事件编号。
|
||||
/// </summary>
|
||||
public override string Id
|
||||
{
|
||||
get { return EventId; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化用户自定义网络错误事件的新实例。
|
||||
/// </summary>
|
||||
public NetworkCustomErrorEventArgs()
|
||||
{
|
||||
NetworkChannel = null;
|
||||
CustomErrorData = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道。
|
||||
/// </summary>
|
||||
public INetworkChannel NetworkChannel { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户自定义错误数据。
|
||||
/// </summary>
|
||||
public object CustomErrorData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建用户自定义网络错误事件。
|
||||
/// </summary>
|
||||
/// <param name="networkChannel">网络频道。</param>
|
||||
/// <param name="customErrorData">用户自定义错误数据。</param>
|
||||
/// <returns>创建的用户自定义网络错误事件。</returns>
|
||||
public static NetworkCustomErrorEventArgs Create(INetworkChannel networkChannel, object customErrorData)
|
||||
{
|
||||
NetworkCustomErrorEventArgs networkCustomErrorEventArgs = ReferencePool.Acquire<NetworkCustomErrorEventArgs>();
|
||||
networkCustomErrorEventArgs.NetworkChannel = networkChannel;
|
||||
networkCustomErrorEventArgs.CustomErrorData = customErrorData;
|
||||
return networkCustomErrorEventArgs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理用户自定义网络错误事件。
|
||||
/// </summary>
|
||||
public override void Clear()
|
||||
{
|
||||
NetworkChannel = null;
|
||||
CustomErrorData = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: edb2b3ba582d4fe9b20eb761b38c127e
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,91 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using System.Net.Sockets;
|
||||
using GameFrameX.Event.Runtime;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络错误事件。
|
||||
/// </summary>
|
||||
public sealed class NetworkErrorEventArgs : GameEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络错误事件编号。
|
||||
/// </summary>
|
||||
public static readonly string EventId = typeof(NetworkErrorEventArgs).FullName;
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络错误事件编号。
|
||||
/// </summary>
|
||||
public override string Id
|
||||
{
|
||||
get { return EventId; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络错误事件的新实例。
|
||||
/// </summary>
|
||||
public NetworkErrorEventArgs()
|
||||
{
|
||||
NetworkChannel = null;
|
||||
ErrorCode = NetworkErrorCode.Unknown;
|
||||
SocketErrorCode = SocketError.Success;
|
||||
ErrorMessage = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道。
|
||||
/// </summary>
|
||||
public INetworkChannel NetworkChannel { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取错误码。
|
||||
/// </summary>
|
||||
public NetworkErrorCode ErrorCode { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取 Socket 错误码。
|
||||
/// </summary>
|
||||
public SocketError SocketErrorCode { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取错误信息。
|
||||
/// </summary>
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建网络错误事件。
|
||||
/// </summary>
|
||||
/// <param name="networkChannel">网络频道。</param>
|
||||
/// <param name="errorCode">错误码。</param>
|
||||
/// <param name="socketErrorCode">Socket 错误码。</param>
|
||||
/// <param name="errorMessage">错误信息。</param>
|
||||
/// <returns>创建的网络错误事件。</returns>
|
||||
public static NetworkErrorEventArgs Create(INetworkChannel networkChannel, NetworkErrorCode errorCode, SocketError socketErrorCode, string errorMessage)
|
||||
{
|
||||
NetworkErrorEventArgs networkErrorEventArgs = ReferencePool.Acquire<NetworkErrorEventArgs>();
|
||||
networkErrorEventArgs.NetworkChannel = networkChannel;
|
||||
networkErrorEventArgs.ErrorCode = errorCode;
|
||||
networkErrorEventArgs.SocketErrorCode = socketErrorCode;
|
||||
networkErrorEventArgs.ErrorMessage = errorMessage;
|
||||
return networkErrorEventArgs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理网络错误事件。
|
||||
/// </summary>
|
||||
public override void Clear()
|
||||
{
|
||||
NetworkChannel = null;
|
||||
ErrorCode = NetworkErrorCode.Unknown;
|
||||
SocketErrorCode = SocketError.Success;
|
||||
ErrorMessage = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 67320bf31d774067b0f7784c80d5958c
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,72 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using GameFrameX.Event.Runtime;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络心跳包丢失事件。
|
||||
/// </summary>
|
||||
public sealed class NetworkMissHeartBeatEventArgs : GameEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络心跳包丢失事件编号。
|
||||
/// </summary>
|
||||
public static readonly string EventId = typeof(NetworkMissHeartBeatEventArgs).FullName;
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络心跳包丢失事件编号。
|
||||
/// </summary>
|
||||
public override string Id
|
||||
{
|
||||
get { return EventId; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络心跳包丢失事件的新实例。
|
||||
/// </summary>
|
||||
public NetworkMissHeartBeatEventArgs()
|
||||
{
|
||||
NetworkChannel = null;
|
||||
MissCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道。
|
||||
/// </summary>
|
||||
public INetworkChannel NetworkChannel { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取心跳包已丢失次数。
|
||||
/// </summary>
|
||||
public int MissCount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建网络心跳包丢失事件。
|
||||
/// </summary>
|
||||
/// <param name="networkChannel">网络频道。</param>
|
||||
/// <param name="missCount">心跳包已丢失次数。</param>
|
||||
/// <returns>创建的网络心跳包丢失事件。</returns>
|
||||
public static NetworkMissHeartBeatEventArgs Create(INetworkChannel networkChannel, int missCount)
|
||||
{
|
||||
NetworkMissHeartBeatEventArgs networkMissHeartBeatEventArgs = ReferencePool.Acquire<NetworkMissHeartBeatEventArgs>();
|
||||
networkMissHeartBeatEventArgs.NetworkChannel = networkChannel;
|
||||
networkMissHeartBeatEventArgs.MissCount = missCount;
|
||||
return networkMissHeartBeatEventArgs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理网络心跳包丢失事件。
|
||||
/// </summary>
|
||||
public override void Clear()
|
||||
{
|
||||
NetworkChannel = null;
|
||||
MissCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 59bbd0035c1c4775b0d18cb3d6eba036
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "GameFrameX.Network.Runtime",
|
||||
"references": [
|
||||
"GameFrameX.Runtime",
|
||||
"GameFrameX.Event.Runtime",
|
||||
"UnityWebSocket.Runtime",
|
||||
"ProtoBuffer.Runtime"
|
||||
],
|
||||
"rootNamespace": "GameFrameX.Network.Runtime",
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.alianblank.unitywebsocket",
|
||||
"expression": "",
|
||||
"define": "ENABLE_GAME_FRAME_X_WEB_SOCKET"
|
||||
},
|
||||
{
|
||||
"name": "com.google.protobuf",
|
||||
"expression": "",
|
||||
"define": "ENABLE_PROTOBUF"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bd1d88a7cb020ac4f8e204d3f5769b3c
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,48 @@
|
|||
using UnityEngine;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public class GameFrameXNetworkCroppingHelper : MonoBehaviour
|
||||
{
|
||||
private void Start()
|
||||
{
|
||||
_ = typeof(DefaultNetworkChannelHelper);
|
||||
_ = typeof(AddressFamily);
|
||||
_ = typeof(DefaultPacketReceiveBodyHandler);
|
||||
_ = typeof(DefaultPacketReceiveHeaderHandler);
|
||||
_ = typeof(DefaultPacketSendBodyHandler);
|
||||
_ = typeof(DefaultPacketSendHeaderHandler);
|
||||
_ = typeof(INetworkChannel);
|
||||
_ = typeof(INetworkChannelHelper);
|
||||
_ = typeof(INetworkManager);
|
||||
_ = typeof(INetworkSocket);
|
||||
_ = typeof(IPacketHandler);
|
||||
_ = typeof(IPacketHeartBeatHandler);
|
||||
_ = typeof(IPacketReceiveBodyHandler);
|
||||
_ = typeof(IPacketReceiveHeaderHandler);
|
||||
_ = typeof(IPacketSendBodyHandler);
|
||||
_ = typeof(IPacketSendHeaderHandler);
|
||||
_ = typeof(IRequestMessage);
|
||||
_ = typeof(IResponseMessage);
|
||||
_ = typeof(MessagePackageObjectAttribute);
|
||||
_ = typeof(MessageTypeHandlerAttribute);
|
||||
_ = typeof(NetworkClosedEventArgs);
|
||||
_ = typeof(NetworkConnectedEventArgs);
|
||||
_ = typeof(NetworkCustomErrorEventArgs);
|
||||
_ = typeof(NetworkErrorCode);
|
||||
_ = typeof(NetworkErrorEventArgs);
|
||||
_ = typeof(NetworkManager);
|
||||
_ = typeof(NetworkManager.ConnectState);
|
||||
_ = typeof(NetworkManager.HeartBeatState);
|
||||
_ = typeof(NetworkManager.NetworkChannelBase);
|
||||
_ = typeof(NetworkManager.ReceiveState);
|
||||
_ = typeof(NetworkManager.SendState);
|
||||
_ = typeof(NetworkMissHeartBeatEventArgs);
|
||||
_ = typeof(Packet);
|
||||
_ = typeof(PacketBase);
|
||||
_ = typeof(ProtoMessageIdHandler);
|
||||
_ = typeof(ServiceType);
|
||||
_ = typeof(NetworkComponent);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 09408fcfcfb0e894f8491d29ef6d510c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7cb8a335950b4bd79eef61c85dd3c800
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2459d700cd854ff796dc0ad4bd1ab228
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,9 @@
|
|||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 客户端发送给服务器的消息的基类接口
|
||||
/// </summary>
|
||||
public interface IRequestMessage
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cfff529910fc4bbe843b6598106526a8
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,9 @@
|
|||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务器返回给客户端的消息基类接口
|
||||
/// </summary>
|
||||
public interface IResponseMessage
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 48caa362979748cda8b0dde9dad75c1a
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,15 @@
|
|||
#if ENABLE_PROTOBUF
|
||||
using ProtoBuf;
|
||||
#endif
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息基类
|
||||
/// </summary>
|
||||
#if ENABLE_PROTOBUF
|
||||
[ProtoContract]
|
||||
#endif
|
||||
public class MessageObject
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3b92cbe17894435bbe4b5d2780c8ff0c
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
#if ENABLE_MESSAGEPACK
|
||||
/// <summary>
|
||||
/// 消息对象标签
|
||||
/// </summary>
|
||||
public class MessagePackageObjectAttribute : MessagePack.MessagePackObjectAttribute
|
||||
{
|
||||
public MessagePackageObjectAttribute() : base(true)
|
||||
{
|
||||
}
|
||||
}
|
||||
#elif ENABLE_PROTOBUF
|
||||
/// <summary>
|
||||
/// 消息对象标签
|
||||
/// </summary>
|
||||
public class MessagePackageObjectAttribute : Attribute
|
||||
{
|
||||
public MessagePackageObjectAttribute() : base()
|
||||
{
|
||||
}
|
||||
}
|
||||
#else
|
||||
/// <summary>
|
||||
/// 消息对象标签
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = true)]
|
||||
public class MessagePackageObjectAttribute
|
||||
{
|
||||
public MessagePackageObjectAttribute() { }
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e16e4772b48a4d8eb6ced977051c7f58
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息处理器
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class MessageTypeHandlerAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息ID,不能重复
|
||||
/// </summary>
|
||||
public int MessageId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 网络消息处理器
|
||||
/// </summary>
|
||||
/// <param name="messageId">消息ID,不能重复</param>
|
||||
public MessageTypeHandlerAttribute(int messageId)
|
||||
{
|
||||
MessageId = messageId;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6491314f168a45e68a5cafe5e6ad7ee5
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f15e40650d3847a59dde940a6daf5cad
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,16 @@
|
|||
using System.Buffers;
|
||||
using GameFrameX.Runtime;
|
||||
using ProtoBuf;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public sealed class DefaultPacketReceiveBodyHandler : IPacketReceiveBodyHandler, IPacketHandler
|
||||
{
|
||||
public bool Handler<T>(object source, int messageId, out T messageObject) where T : MessageObject
|
||||
{
|
||||
var messageType = ProtoMessageIdHandler.GetRespTypeById(messageId);
|
||||
messageObject = (T)SerializerHelper.Deserialize(source as byte[], messageType);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 67720f87151c431c9b7b2b732dbc5718
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using GameFrameX.Runtime;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public sealed class DefaultPacketReceiveHeaderHandler : IPacketReceiveHeaderHandler, IPacketHandler
|
||||
{
|
||||
public int PacketLength { get; private set; }
|
||||
public int Id { get; private set; }
|
||||
|
||||
|
||||
public bool Handler(object source)
|
||||
{
|
||||
byte[] reader = source as byte[];
|
||||
if (reader == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// packetLength
|
||||
int offest = 0;
|
||||
int packetLength = reader.ReadInt(ref offest); //4
|
||||
PacketLength = packetLength;
|
||||
// timestamp
|
||||
long timestamp = reader.ReadLong(ref offest); //8
|
||||
// MsgId
|
||||
int msgId = reader.ReadInt(ref offest); //4
|
||||
Id = msgId;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 网络包长度
|
||||
/// </summary>
|
||||
private const int NetPacketLength = 4;
|
||||
|
||||
// 消息码
|
||||
private const int NetCmdIdLength = 4;
|
||||
|
||||
// 消息时间戳
|
||||
private const int NetTicketLength = 8;
|
||||
|
||||
public DefaultPacketReceiveHeaderHandler()
|
||||
{
|
||||
PacketHeaderLength = NetPacketLength + NetTicketLength + NetCmdIdLength;
|
||||
}
|
||||
|
||||
public int PacketHeaderLength { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: abd509e066aa48f3822f2048efb12af9
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,14 @@
|
|||
using System.IO;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public sealed class DefaultPacketSendBodyHandler : IPacketSendBodyHandler, IPacketHandler
|
||||
{
|
||||
public bool Handler(byte[] messageBodyBuffer, MemoryStream cachedStream, Stream destination)
|
||||
{
|
||||
cachedStream.Write(messageBodyBuffer, 0, messageBodyBuffer.Length);
|
||||
cachedStream.WriteTo(destination);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b96f0f08c4364b86ade3333d44fbcf35
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,75 @@
|
|||
using System.IO;
|
||||
using GameFrameX.Runtime;
|
||||
using ProtoBuf;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public sealed class DefaultPacketSendHeaderHandler : IPacketSendHeaderHandler, IPacketHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络包长度
|
||||
/// </summary>
|
||||
private const int NetPacketLength = 4;
|
||||
|
||||
// 消息码
|
||||
private const int NetCmdIdLength = 4;
|
||||
|
||||
// 排序
|
||||
private const int NetOrderLength = 4;
|
||||
|
||||
// 消息时间戳
|
||||
private const int NetTicketLength = 8;
|
||||
|
||||
|
||||
public DefaultPacketSendHeaderHandler()
|
||||
{
|
||||
// 4 + 8 + 4 + 4
|
||||
PacketHeaderLength = NetPacketLength + NetTicketLength + NetOrderLength + NetCmdIdLength;
|
||||
_cachedByte = new byte[PacketHeaderLength];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息包头长度
|
||||
/// </summary>
|
||||
public int PacketHeaderLength { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络消息包协议编号。
|
||||
/// </summary>
|
||||
public int Id { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络消息包长度。
|
||||
/// </summary>
|
||||
public int PacketLength { get; private set; }
|
||||
|
||||
private const int Magic = 0x1234;
|
||||
|
||||
int count = 0;
|
||||
private readonly byte[] _cachedByte;
|
||||
|
||||
public bool Handler<T>(T messageObject, MemoryStream cachedStream, out byte[] messageBodyBuffer) where T : MessageObject
|
||||
{
|
||||
cachedStream.Seek(0, SeekOrigin.Begin);
|
||||
cachedStream.SetLength(0);
|
||||
|
||||
messageBodyBuffer = SerializerHelper.Serialize(messageObject);
|
||||
var messageType = messageObject.GetType();
|
||||
Id = ProtoMessageIdHandler.GetReqMessageIdByType(messageType);
|
||||
var messageLength = messageBodyBuffer.Length;
|
||||
PacketLength = PacketHeaderLength + messageLength;
|
||||
int magic = Magic + ++count;
|
||||
magic ^= Magic << 8;
|
||||
magic ^= PacketLength;
|
||||
|
||||
int offset = 0;
|
||||
|
||||
_cachedByte.WriteInt(PacketLength, ref offset);
|
||||
_cachedByte.WriteLong(GameTimeHelper.UnixTimeMilliseconds(), ref offset);
|
||||
_cachedByte.WriteInt(Id, ref offset);
|
||||
_cachedByte.WriteInt(messageLength, ref offset);
|
||||
cachedStream.Write(_cachedByte, 0, PacketHeaderLength);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7fc1e6db3167413fbde9df4ce2f75d3d
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4558070d78b34c3ca6c144261757f1fa
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,30 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络地址类型。
|
||||
/// </summary>
|
||||
public enum AddressFamily : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 未知。
|
||||
/// </summary>
|
||||
Unknown = 0,
|
||||
|
||||
/// <summary>
|
||||
/// IP 版本 4。
|
||||
/// </summary>
|
||||
IPv4,
|
||||
|
||||
/// <summary>
|
||||
/// IP 版本 6。
|
||||
/// </summary>
|
||||
IPv6
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9a2b7b3d3d394ace93aa66899c567726
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,160 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络频道接口。
|
||||
/// </summary>
|
||||
public interface INetworkChannel
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取网络频道名称。
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道所使用的 Socket。
|
||||
/// </summary>
|
||||
INetworkSocket Socket { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取是否已连接。
|
||||
/// </summary>
|
||||
bool Connected { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络地址类型。
|
||||
/// </summary>
|
||||
AddressFamily AddressFamily { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取要发送的消息包数量。
|
||||
/// </summary>
|
||||
int SendPacketCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取累计发送的消息包数量。
|
||||
/// </summary>
|
||||
int SentPacketCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取已接收未处理的消息包数量。
|
||||
/// </summary>
|
||||
int ReceivePacketCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取累计已接收的消息包数量。
|
||||
/// </summary>
|
||||
int ReceivedPacketCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置当收到消息包时是否重置心跳流逝时间。
|
||||
/// </summary>
|
||||
bool ResetHeartBeatElapseSecondsWhenReceivePacket { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取丢失心跳的次数。
|
||||
/// </summary>
|
||||
int MissHeartBeatCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置心跳间隔时长,以秒为单位。
|
||||
/// </summary>
|
||||
float HeartBeatInterval { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取心跳等待时长,以秒为单位。
|
||||
/// </summary>
|
||||
float HeartBeatElapseSeconds { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 消息发送包头处理器
|
||||
/// </summary>
|
||||
IPacketSendHeaderHandler PacketSendHeaderHandler { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 消息发送内容处理器
|
||||
/// </summary>
|
||||
IPacketSendBodyHandler PacketSendBodyHandler { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 心跳消息处理器
|
||||
/// </summary>
|
||||
IPacketHeartBeatHandler PacketHeartBeatHandler { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 消息接收包头处理器
|
||||
/// </summary>
|
||||
IPacketReceiveHeaderHandler PacketReceiveHeaderHandler { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 消息接收内容处理器
|
||||
/// </summary>
|
||||
IPacketReceiveBodyHandler PacketReceiveBodyHandler { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 注册网络消息包处理函数。
|
||||
/// </summary>
|
||||
/// <param name="handler">要注册的网络消息包处理函数。</param>
|
||||
void RegisterHandler(IPacketSendHeaderHandler handler);
|
||||
|
||||
/// <summary>
|
||||
/// 注册网络消息包处理函数。
|
||||
/// </summary>
|
||||
/// <param name="handler">要注册的网络消息包处理函数。</param>
|
||||
void RegisterHandler(IPacketSendBodyHandler handler);
|
||||
|
||||
/// <summary>
|
||||
/// 注册网络消息包处理函数。
|
||||
/// </summary>
|
||||
/// <param name="handler">要注册的网络消息包处理函数。</param>
|
||||
void RegisterHandler(IPacketReceiveHeaderHandler handler);
|
||||
|
||||
/// <summary>
|
||||
/// 注册网络消息包处理函数。
|
||||
/// </summary>
|
||||
/// <param name="handler">要注册的网络消息包处理函数。</param>
|
||||
void RegisterHandler(IPacketReceiveBodyHandler handler);
|
||||
|
||||
/// <summary>
|
||||
/// 注册网络消息心跳处理函数,用于处理心跳消息
|
||||
/// </summary>
|
||||
/// <param name="handler">要注册的网络消息包处理函数</param>
|
||||
void RegisterHandler(IPacketHeartBeatHandler handler);
|
||||
|
||||
/// <summary>
|
||||
/// 设置默认事件处理函数。
|
||||
/// </summary>
|
||||
/// <param name="handler">要设置的默认事件处理函数。</param>
|
||||
void SetDefaultHandler(EventHandler<Packet> handler);
|
||||
|
||||
/// <summary>
|
||||
/// 连接到远程主机。
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">远程主机的 IP 地址。</param>
|
||||
/// <param name="port">远程主机的端口号。</param>
|
||||
/// <param name="userData">用户自定义数据。</param>
|
||||
void Connect(IPAddress ipAddress, int port, object userData = null);
|
||||
|
||||
/// <summary>
|
||||
/// 关闭网络频道。
|
||||
/// </summary>
|
||||
void Close();
|
||||
|
||||
/// <summary>
|
||||
/// 向远程主机发送消息包。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">消息包类型。</typeparam>
|
||||
/// <param name="messageObject">要发送的消息包。</param>
|
||||
void Send<T>(T messageObject) where T : MessageObject;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d09e24362c0c4247b2e3bf09f3d3fb15
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,75 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络频道辅助器接口。
|
||||
/// </summary>
|
||||
public interface INetworkChannelHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化网络频道辅助器。
|
||||
/// </summary>
|
||||
/// <param name="networkChannel">网络频道。</param>
|
||||
void Initialize(INetworkChannel networkChannel);
|
||||
|
||||
/// <summary>
|
||||
/// 关闭并清理网络频道辅助器。
|
||||
/// </summary>
|
||||
void Shutdown();
|
||||
|
||||
/// <summary>
|
||||
/// 准备进行连接。
|
||||
/// </summary>
|
||||
void PrepareForConnecting();
|
||||
|
||||
/// <summary>
|
||||
/// 发送心跳消息包。
|
||||
/// </summary>
|
||||
/// <returns>是否发送心跳消息包成功。</returns>
|
||||
bool SendHeartBeat();
|
||||
|
||||
/// <summary>
|
||||
/// 序列化消息头
|
||||
/// </summary>
|
||||
/// <param name="messageObject"></param>
|
||||
/// <param name="destination"></param>
|
||||
/// <param name="messageBodyBuffer"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
bool SerializePacketHeader<T>(T messageObject, Stream destination, out byte[] messageBodyBuffer) where T : MessageObject;
|
||||
|
||||
/// <summary>
|
||||
/// 序列化消息包。
|
||||
/// </summary>
|
||||
/// <param name="messageBodyBuffer">要序列化的消息包。</param>
|
||||
/// <param name="destination">要序列化的目标流。</param>
|
||||
/// <returns>是否序列化成功。</returns>
|
||||
bool SerializePacketBody(byte[] messageBodyBuffer, Stream destination);
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化消息包头。
|
||||
/// </summary>
|
||||
/// <param name="source">要反序列化的来源流。</param>
|
||||
/// <returns>反序列化后的消息包头。</returns>
|
||||
bool DeserializePacketHeader(object source);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化消息包。
|
||||
/// </summary>
|
||||
/// <param name="source">要反序列化的来源流。</param>
|
||||
/// <param name="messageId">消息ID</param>
|
||||
/// <param name="messageObject"></param>
|
||||
/// <returns>反序列化后的消息包。</returns>
|
||||
bool DeserializePacketBody(object source, int messageId, out MessageObject messageObject);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: af2db2c8580c4cbfbb3b0bdd2847c4c9
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,89 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络管理器接口。
|
||||
/// </summary>
|
||||
public interface INetworkManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取网络频道数量。
|
||||
/// </summary>
|
||||
int NetworkChannelCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 网络连接成功事件。
|
||||
/// </summary>
|
||||
event EventHandler<NetworkConnectedEventArgs> NetworkConnected;
|
||||
|
||||
/// <summary>
|
||||
/// 网络连接关闭事件。
|
||||
/// </summary>
|
||||
event EventHandler<NetworkClosedEventArgs> NetworkClosed;
|
||||
|
||||
/// <summary>
|
||||
/// 网络心跳包丢失事件。
|
||||
/// </summary>
|
||||
event EventHandler<NetworkMissHeartBeatEventArgs> NetworkMissHeartBeat;
|
||||
|
||||
/// <summary>
|
||||
/// 网络错误事件。
|
||||
/// </summary>
|
||||
event EventHandler<NetworkErrorEventArgs> NetworkError;
|
||||
|
||||
/// <summary>
|
||||
/// 用户自定义网络错误事件。
|
||||
/// </summary>
|
||||
event EventHandler<NetworkCustomErrorEventArgs> NetworkCustomError;
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否存在网络频道。
|
||||
/// </summary>
|
||||
/// <param name="channelName">网络频道名称。</param>
|
||||
/// <returns>是否存在网络频道。</returns>
|
||||
bool HasNetworkChannel(string channelName);
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道。
|
||||
/// </summary>
|
||||
/// <param name="channelName">网络频道名称。</param>
|
||||
/// <returns>要获取的网络频道。</returns>
|
||||
INetworkChannel GetNetworkChannel(string channelName);
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有网络频道。
|
||||
/// </summary>
|
||||
/// <returns>所有网络频道。</returns>
|
||||
INetworkChannel[] GetAllNetworkChannels();
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有网络频道。
|
||||
/// </summary>
|
||||
/// <param name="results">所有网络频道。</param>
|
||||
void GetAllNetworkChannels(List<INetworkChannel> results);
|
||||
|
||||
/// <summary>
|
||||
/// 创建网络频道。
|
||||
/// </summary>
|
||||
/// <param name="channelName">网络频道名称。</param>
|
||||
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
||||
/// <returns>要创建的网络频道。</returns>
|
||||
INetworkChannel CreateNetworkChannel(string channelName, INetworkChannelHelper networkChannelHelper);
|
||||
|
||||
/// <summary>
|
||||
/// 销毁网络频道。
|
||||
/// </summary>
|
||||
/// <param name="channelName">网络频道名称。</param>
|
||||
/// <returns>是否销毁网络频道成功。</returns>
|
||||
bool DestroyNetworkChannel(string channelName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6e5038d2f7c2458183a1982de7e8297f
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,46 @@
|
|||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络套接字接口。
|
||||
/// </summary>
|
||||
public interface INetworkSocket
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取是否已连接。
|
||||
/// </summary>
|
||||
bool IsConnected { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取本地终结点。
|
||||
/// </summary>
|
||||
EndPoint LocalEndPoint { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取远程终结点。
|
||||
/// </summary>
|
||||
EndPoint RemoteEndPoint { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置接收缓冲区大小。
|
||||
/// </summary>
|
||||
int ReceiveBufferSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置发送缓冲区大小。
|
||||
/// </summary>
|
||||
int SendBufferSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关闭网络套接字。
|
||||
/// </summary>
|
||||
void Shutdown();
|
||||
|
||||
/// <summary>
|
||||
/// 关闭网络套接字并释放资源。
|
||||
/// </summary>
|
||||
void Close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9ff2740bbabd40bda79fe61c1d59802f
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,6 @@
|
|||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public interface IPacketHandler
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1e27d90703174b8fa72a5ea5292b772b
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,24 @@
|
|||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息心跳包接口。
|
||||
/// </summary>
|
||||
public interface IPacketHeartBeatHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// 每次心跳的间隔
|
||||
/// </summary>
|
||||
float HeartBeatInterval { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 几次心跳丢失。触发断开网络
|
||||
/// </summary>
|
||||
int MissHeartBeatCountByClose { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 处理器
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
MessageObject Handler();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ebf5176432074099ae1dca6c555f6332
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,18 @@
|
|||
using System.Buffers;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息包处理器接口。
|
||||
/// </summary>
|
||||
public interface IPacketReceiveBodyHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息包处理函数。
|
||||
/// </summary>
|
||||
/// <param name="source">网络消息包源。</param>
|
||||
/// <param name="messageId">消息包标识,用于映射消息包</param>
|
||||
/// <param name="messageObject"></param>
|
||||
bool Handler<T>(object source,int messageId, out T messageObject) where T : MessageObject;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f8089c34f2c54e9cb9fd90b75d487c3c
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,34 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using System.Buffers;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息包头接口。
|
||||
/// </summary>
|
||||
public interface IPacketReceiveHeaderHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息包头长度
|
||||
/// </summary>
|
||||
int PacketHeaderLength { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络消息包长度。
|
||||
/// </summary>
|
||||
int PacketLength { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络消息包协议编号。
|
||||
/// </summary>
|
||||
int Id { get; }
|
||||
|
||||
bool Handler(object source);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 095ef321684f44c4947309c5a156ad03
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,26 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息包处理器接口。
|
||||
/// </summary>
|
||||
public interface IPacketSendBodyHandler
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="messageBodyBuffer"></param>
|
||||
/// <param name="cachedStream"></param>
|
||||
/// <param name="destination"></param>
|
||||
/// <returns></returns>
|
||||
bool Handler(byte[] messageBodyBuffer, MemoryStream cachedStream, Stream destination);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f78783fd0f4941e0a8e3aa2991e1aa67
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,35 @@
|
|||
using System.IO;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息包头接口。
|
||||
/// </summary>
|
||||
public interface IPacketSendHeaderHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息包头长度
|
||||
/// </summary>
|
||||
int PacketHeaderLength { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络消息包协议编号。
|
||||
/// </summary>
|
||||
int Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络消息包长度。
|
||||
/// </summary>
|
||||
int PacketLength { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 处理消息
|
||||
/// </summary>
|
||||
/// <param name="messageObject">消息对象</param>
|
||||
/// <param name="cachedStream">缓存流</param>
|
||||
/// <param name="messageBodyBuffer">消息序列化完的二进制数组</param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
bool Handler<T>(T messageObject, MemoryStream cachedStream, out byte[] messageBodyBuffer) where T : MessageObject;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ec256791814648aa82526abaf98189a9
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,218 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using GameFrameX;
|
||||
using GameFrameX.Event;
|
||||
using GameFrameX.Event.Runtime;
|
||||
using GameFrameX.Network;
|
||||
using GameFrameX.Runtime;
|
||||
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public class DefaultNetworkChannelHelper : INetworkChannelHelper, IReference
|
||||
{
|
||||
private MemoryStream _cachedStream;
|
||||
private INetworkChannel _netChannel;
|
||||
|
||||
public DefaultNetworkChannelHelper()
|
||||
{
|
||||
// _s2cPacketTypes = new Dictionary<int, Type>();
|
||||
_cachedStream = new MemoryStream(1024);
|
||||
_netChannel = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取事件组件。
|
||||
/// </summary>
|
||||
public EventComponent Event
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_event == null)
|
||||
{
|
||||
_event = GameEntry.GetComponent<EventComponent>();
|
||||
}
|
||||
|
||||
return _event;
|
||||
}
|
||||
}
|
||||
|
||||
private static EventComponent _event;
|
||||
|
||||
public void Initialize(INetworkChannel netChannel)
|
||||
{
|
||||
_netChannel = netChannel;
|
||||
// 反射注册包和包处理函数。
|
||||
var packetReceiveHeaderHandlerBaseType = typeof(IPacketReceiveHeaderHandler);
|
||||
var packetReceiveBodyHandlerBaseType = typeof(IPacketReceiveBodyHandler);
|
||||
var packetSendHeaderHandlerBaseType = typeof(IPacketSendHeaderHandler);
|
||||
var packetSendBodyHandlerBaseType = typeof(IPacketSendBodyHandler);
|
||||
var packetHeartBeatHandlerBaseType = typeof(IPacketHeartBeatHandler);
|
||||
var packetHandlerBaseType = typeof(IPacketHandler);
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
var types = assembly.GetTypes();
|
||||
foreach (var type in types)
|
||||
{
|
||||
if (!type.IsClass || type.IsAbstract)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!type.IsImplWithInterface(packetHandlerBaseType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type.IsImplWithInterface(packetReceiveHeaderHandlerBaseType))
|
||||
{
|
||||
var packetHandler = (IPacketReceiveHeaderHandler)Activator.CreateInstance(type);
|
||||
_netChannel.RegisterHandler(packetHandler);
|
||||
}
|
||||
else if (type.IsImplWithInterface(packetReceiveBodyHandlerBaseType))
|
||||
{
|
||||
var packetHandler = (IPacketReceiveBodyHandler)Activator.CreateInstance(type);
|
||||
_netChannel.RegisterHandler(packetHandler);
|
||||
}
|
||||
else if (type.IsImplWithInterface(packetSendHeaderHandlerBaseType))
|
||||
{
|
||||
var packetHandler = (IPacketSendHeaderHandler)Activator.CreateInstance(type);
|
||||
_netChannel.RegisterHandler(packetHandler);
|
||||
}
|
||||
else if (type.IsImplWithInterface(packetSendBodyHandlerBaseType))
|
||||
{
|
||||
var packetHandler = (IPacketSendBodyHandler)Activator.CreateInstance(type);
|
||||
_netChannel.RegisterHandler(packetHandler);
|
||||
}
|
||||
else if (type.IsImplWithInterface(packetHeartBeatHandlerBaseType))
|
||||
{
|
||||
var packetHandler = (IPacketHeartBeatHandler)Activator.CreateInstance(type);
|
||||
_netChannel.RegisterHandler(packetHandler);
|
||||
}
|
||||
}
|
||||
|
||||
Event.Subscribe(NetworkConnectedEventArgs.EventId, OnNetConnected);
|
||||
Event.Subscribe(NetworkClosedEventArgs.EventId, OnNetClosed);
|
||||
Event.Subscribe(NetworkMissHeartBeatEventArgs.EventId, OnNetMissHeartBeat);
|
||||
Event.Subscribe(NetworkErrorEventArgs.EventId, OnNetError);
|
||||
Event.Subscribe(NetworkConnectedEventArgs.EventId, OnNetCustomError);
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
Event.Unsubscribe(NetworkConnectedEventArgs.EventId, OnNetConnected);
|
||||
Event.Unsubscribe(NetworkClosedEventArgs.EventId, OnNetClosed);
|
||||
Event.Unsubscribe(NetworkMissHeartBeatEventArgs.EventId, OnNetMissHeartBeat);
|
||||
Event.Unsubscribe(NetworkErrorEventArgs.EventId, OnNetError);
|
||||
Event.Unsubscribe(NetworkConnectedEventArgs.EventId, OnNetCustomError);
|
||||
_netChannel = null;
|
||||
}
|
||||
|
||||
public void PrepareForConnecting()
|
||||
{
|
||||
_netChannel.Socket.ReceiveBufferSize = 1024 * 1024 * 5;
|
||||
_netChannel.Socket.SendBufferSize = 1024 * 1024 * 5;
|
||||
}
|
||||
|
||||
public bool SendHeartBeat()
|
||||
{
|
||||
var message = _netChannel.PacketHeartBeatHandler.Handler();
|
||||
_netChannel.Send(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SerializePacketHeader<T>(T messageObject, Stream destination, out byte[] messageBodyBuffer) where T : MessageObject
|
||||
{
|
||||
GameFrameworkGuard.NotNull(_netChannel, nameof(_netChannel));
|
||||
GameFrameworkGuard.NotNull(_netChannel.PacketSendHeaderHandler, nameof(_netChannel.PacketSendHeaderHandler));
|
||||
GameFrameworkGuard.NotNull(messageObject, nameof(messageObject));
|
||||
GameFrameworkGuard.NotNull(destination, nameof(destination));
|
||||
|
||||
return _netChannel.PacketSendHeaderHandler.Handler(messageObject, _cachedStream, out messageBodyBuffer);
|
||||
}
|
||||
|
||||
public bool SerializePacketBody(byte[] messageBodyBuffer, Stream destination)
|
||||
{
|
||||
GameFrameworkGuard.NotNull(_netChannel, nameof(_netChannel));
|
||||
GameFrameworkGuard.NotNull(_netChannel.PacketSendHeaderHandler, nameof(_netChannel.PacketSendHeaderHandler));
|
||||
GameFrameworkGuard.NotNull(_netChannel.PacketSendBodyHandler, nameof(_netChannel.PacketSendBodyHandler));
|
||||
GameFrameworkGuard.NotNull(messageBodyBuffer, nameof(messageBodyBuffer));
|
||||
GameFrameworkGuard.NotNull(destination, nameof(destination));
|
||||
|
||||
return _netChannel.PacketSendBodyHandler.Handler(messageBodyBuffer, _cachedStream, destination);
|
||||
}
|
||||
|
||||
public bool DeserializePacketHeader(object source)
|
||||
{
|
||||
GameFrameworkGuard.NotNull(source, nameof(source));
|
||||
|
||||
return _netChannel.PacketReceiveHeaderHandler.Handler(source);
|
||||
}
|
||||
|
||||
public bool DeserializePacketBody(object source, int messageId, out MessageObject messageObject)
|
||||
{
|
||||
GameFrameworkGuard.NotNull(source, nameof(source));
|
||||
|
||||
return _netChannel.PacketReceiveBodyHandler.Handler(source, messageId, out messageObject);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_cachedStream = null;
|
||||
_netChannel = null;
|
||||
}
|
||||
|
||||
private void OnNetConnected(object sender, GameEventArgs e)
|
||||
{
|
||||
var ne = e as NetworkConnectedEventArgs;
|
||||
if (ne == null || ne.NetworkChannel != _netChannel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Info("网络连接成功......");
|
||||
}
|
||||
|
||||
private void OnNetClosed(object sender, GameEventArgs e)
|
||||
{
|
||||
var ne = e as NetworkClosedEventArgs;
|
||||
if (ne == null || ne.NetworkChannel != _netChannel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Info("网络连接关闭......");
|
||||
}
|
||||
|
||||
private void OnNetMissHeartBeat(object sender, GameEventArgs e)
|
||||
{
|
||||
var ne = e as NetworkMissHeartBeatEventArgs;
|
||||
if (ne == null || ne.NetworkChannel != _netChannel) return;
|
||||
Log.Warning(Utility.Text.Format("Network channel '{0}' miss heart beat '{1}' times.", ne.NetworkChannel.Name, ne.MissCount));
|
||||
// if (ne.MissCount < 2) return;
|
||||
// ne.NetChannel.Close();
|
||||
}
|
||||
|
||||
private void OnNetError(object sender, GameEventArgs e)
|
||||
{
|
||||
var ne = e as NetworkErrorEventArgs;
|
||||
if (ne == null || ne.NetworkChannel != _netChannel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Error(Utility.Text.Format("Network channel '{0}' error, error code is '{1}', error message is '{2}'.", ne.NetworkChannel.Name, ne.ErrorCode, ne.ErrorMessage));
|
||||
//ne.NetworkChannel.Close();
|
||||
}
|
||||
|
||||
private void OnNetCustomError(object sender, GameEventArgs e)
|
||||
{
|
||||
var ne = e as NetworkCustomErrorEventArgs;
|
||||
if (ne == null || ne.NetworkChannel != _netChannel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 87137372edf04fdfaf39110a047ac72f
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,60 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络错误码。
|
||||
/// </summary>
|
||||
public enum NetworkErrorCode : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 未知错误。
|
||||
/// </summary>
|
||||
Unknown = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 地址族错误。
|
||||
/// </summary>
|
||||
AddressFamilyError,
|
||||
|
||||
/// <summary>
|
||||
/// Socket 错误。
|
||||
/// </summary>
|
||||
SocketError,
|
||||
|
||||
/// <summary>
|
||||
/// 连接错误。
|
||||
/// </summary>
|
||||
ConnectError,
|
||||
|
||||
/// <summary>
|
||||
/// 发送错误。
|
||||
/// </summary>
|
||||
SendError,
|
||||
|
||||
/// <summary>
|
||||
/// 接收错误。
|
||||
/// </summary>
|
||||
ReceiveError,
|
||||
|
||||
/// <summary>
|
||||
/// 序列化错误。
|
||||
/// </summary>
|
||||
SerializeError,
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化消息包头错误。
|
||||
/// </summary>
|
||||
DeserializePacketHeaderError,
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化消息包错误。
|
||||
/// </summary>
|
||||
DeserializePacketError
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 356d13a0a41447c38f37eaa891861ce7
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,40 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public sealed partial class NetworkManager
|
||||
{
|
||||
public sealed class ConnectState
|
||||
{
|
||||
private readonly INetworkSocket _socket;
|
||||
private readonly object _userData;
|
||||
|
||||
public ConnectState(INetworkSocket socket, object userData)
|
||||
{
|
||||
_socket = socket;
|
||||
_userData = userData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Socket
|
||||
/// </summary>
|
||||
public INetworkSocket Socket
|
||||
{
|
||||
get { return _socket; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户自定义数据
|
||||
/// </summary>
|
||||
public object UserData
|
||||
{
|
||||
get { return _userData; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2ffa6d8aff2d402f9a993390ea8995de
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,59 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public sealed partial class NetworkManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 心跳状态
|
||||
/// </summary>
|
||||
public sealed class HeartBeatState
|
||||
{
|
||||
private float _heartBeatElapseSeconds;
|
||||
private int _missHeartBeatCount;
|
||||
|
||||
public HeartBeatState()
|
||||
{
|
||||
_heartBeatElapseSeconds = 0f;
|
||||
_missHeartBeatCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 心跳间隔时长
|
||||
/// </summary>
|
||||
public float HeartBeatElapseSeconds
|
||||
{
|
||||
get => _heartBeatElapseSeconds;
|
||||
set => _heartBeatElapseSeconds = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 心跳丢失次数
|
||||
/// </summary>
|
||||
public int MissHeartBeatCount
|
||||
{
|
||||
get => _missHeartBeatCount;
|
||||
set => _missHeartBeatCount = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置心跳数据=>保活
|
||||
/// </summary>
|
||||
/// <param name="resetHeartBeatElapseSeconds">是否重置心跳流逝时长</param>
|
||||
public void Reset(bool resetHeartBeatElapseSeconds)
|
||||
{
|
||||
if (resetHeartBeatElapseSeconds)
|
||||
{
|
||||
_heartBeatElapseSeconds = 0f;
|
||||
}
|
||||
|
||||
_missHeartBeatCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: db7880af581d48f2a75f72e65ce55eda
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,784 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using GameFrameX.Runtime;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public sealed partial class NetworkManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络频道基类。
|
||||
/// </summary>
|
||||
public abstract class NetworkChannelBase : INetworkChannel, IDisposable
|
||||
{
|
||||
private const float DefaultHeartBeatInterval = 30f;
|
||||
private const int DefaultMissHeartBeatCountByClose = 10;
|
||||
|
||||
private readonly string _name;
|
||||
protected readonly Queue<MessageObject> PSendPacketPool;
|
||||
protected readonly EventPool<Packet> PReceivePacketPool;
|
||||
protected readonly INetworkChannelHelper PNetworkChannelHelper;
|
||||
protected AddressFamily PAddressFamily;
|
||||
protected bool PResetHeartBeatElapseSecondsWhenReceivePacket;
|
||||
protected float PHeartBeatInterval;
|
||||
protected int MissHeartBeatCountByClose;
|
||||
protected INetworkSocket PSocket;
|
||||
protected readonly SendState PSendState;
|
||||
protected readonly ReceiveState PReceiveState;
|
||||
protected readonly HeartBeatState PHeartBeatState;
|
||||
protected int PSentPacketCount;
|
||||
protected int PReceivedPacketCount;
|
||||
|
||||
protected bool PActive
|
||||
{
|
||||
get => _pActive;
|
||||
set
|
||||
{
|
||||
_pActive = value;
|
||||
Log.Debug(value);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
|
||||
private IPacketSendHeaderHandler _packetSendHeaderHandler;
|
||||
private IPacketSendBodyHandler _packetSendBodyHandler;
|
||||
private IPacketReceiveHeaderHandler _packetReceiveHeaderHandler;
|
||||
private IPacketReceiveBodyHandler _packetReceiveBodyHandler;
|
||||
private IPacketHeartBeatHandler _packetHeartBeatHandler;
|
||||
|
||||
public Action<NetworkChannelBase, object> NetworkChannelConnected;
|
||||
public Action<NetworkChannelBase> NetworkChannelClosed;
|
||||
public Action<NetworkChannelBase, int> NetworkChannelMissHeartBeat;
|
||||
public Action<NetworkChannelBase, NetworkErrorCode, SocketError, string> NetworkChannelError;
|
||||
public Action<NetworkChannelBase, object> NetworkChannelCustomError;
|
||||
private bool _pActive;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络频道基类的新实例。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
||||
public NetworkChannelBase(string name, INetworkChannelHelper networkChannelHelper)
|
||||
{
|
||||
_name = name ?? string.Empty;
|
||||
PSendPacketPool = new Queue<MessageObject>(128);
|
||||
PReceivePacketPool = new EventPool<Packet>(EventPoolMode.Default);
|
||||
PNetworkChannelHelper = networkChannelHelper;
|
||||
PAddressFamily = AddressFamily.Unknown;
|
||||
PResetHeartBeatElapseSecondsWhenReceivePacket = false;
|
||||
PHeartBeatInterval = DefaultHeartBeatInterval;
|
||||
MissHeartBeatCountByClose = DefaultMissHeartBeatCountByClose;
|
||||
PSocket = null;
|
||||
PSendState = new SendState();
|
||||
PReceiveState = new ReceiveState();
|
||||
PHeartBeatState = new HeartBeatState();
|
||||
PSentPacketCount = 0;
|
||||
PReceivedPacketCount = 0;
|
||||
PActive = false;
|
||||
_disposed = false;
|
||||
|
||||
NetworkChannelConnected = null;
|
||||
NetworkChannelClosed = null;
|
||||
NetworkChannelMissHeartBeat = null;
|
||||
NetworkChannelError = null;
|
||||
NetworkChannelCustomError = null;
|
||||
|
||||
networkChannelHelper.Initialize(this);
|
||||
}
|
||||
|
||||
#region 属性
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道名称。
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道所使用的 Socket。
|
||||
/// </summary>
|
||||
public INetworkSocket Socket
|
||||
{
|
||||
get { return PSocket; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取是否已连接。
|
||||
/// </summary>
|
||||
public bool Connected
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PSocket != null)
|
||||
{
|
||||
return PSocket.IsConnected;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络地址类型。
|
||||
/// </summary>
|
||||
public AddressFamily AddressFamily
|
||||
{
|
||||
get { return PAddressFamily; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取要发送的消息包数量。
|
||||
/// </summary>
|
||||
public int SendPacketCount
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (PSendPacketPool)
|
||||
{
|
||||
return PSendPacketPool.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取累计发送的消息包数量。
|
||||
/// </summary>
|
||||
public int SentPacketCount
|
||||
{
|
||||
get { return PSentPacketCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取已接收未处理的消息包数量。
|
||||
/// </summary>
|
||||
public int ReceivePacketCount
|
||||
{
|
||||
get { return PReceivePacketPool.EventCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取累计已接收的消息包数量。
|
||||
/// </summary>
|
||||
public int ReceivedPacketCount
|
||||
{
|
||||
get { return PReceivedPacketCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置当收到消息包时是否重置心跳流逝时间。
|
||||
/// </summary>
|
||||
public bool ResetHeartBeatElapseSecondsWhenReceivePacket
|
||||
{
|
||||
get { return PResetHeartBeatElapseSecondsWhenReceivePacket; }
|
||||
set { PResetHeartBeatElapseSecondsWhenReceivePacket = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取丢失心跳的次数。
|
||||
/// </summary>
|
||||
public int MissHeartBeatCount
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (PHeartBeatState)
|
||||
{
|
||||
return PHeartBeatState.MissHeartBeatCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置心跳间隔时长,以秒为单位。
|
||||
/// </summary>
|
||||
public float HeartBeatInterval
|
||||
{
|
||||
get { return PHeartBeatInterval; }
|
||||
set { PHeartBeatInterval = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取心跳等待时长,以秒为单位。
|
||||
/// </summary>
|
||||
public float HeartBeatElapseSeconds
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (PHeartBeatState)
|
||||
{
|
||||
return PHeartBeatState.HeartBeatElapseSeconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息发送包头处理器
|
||||
/// </summary>
|
||||
public IPacketSendHeaderHandler PacketSendHeaderHandler
|
||||
{
|
||||
get { return _packetSendHeaderHandler; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息发送内容处理器
|
||||
/// </summary>
|
||||
public IPacketSendBodyHandler PacketSendBodyHandler
|
||||
{
|
||||
get { return _packetSendBodyHandler; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息接收包头处理器
|
||||
/// </summary>
|
||||
public IPacketReceiveHeaderHandler PacketReceiveHeaderHandler
|
||||
{
|
||||
get { return _packetReceiveHeaderHandler; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 心跳消息处理器
|
||||
/// </summary>
|
||||
public IPacketHeartBeatHandler PacketHeartBeatHandler
|
||||
{
|
||||
get { return _packetHeartBeatHandler; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息接收内容处理器
|
||||
/// </summary>
|
||||
public IPacketReceiveBodyHandler PacketReceiveBodyHandler
|
||||
{
|
||||
get { return _packetReceiveBodyHandler; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 网络频道轮询。
|
||||
/// </summary>
|
||||
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
|
||||
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
|
||||
public virtual void Update(float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
if (PSocket == null || !PActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessSend();
|
||||
ProcessReceive();
|
||||
if (PSocket == null || !PActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PReceivePacketPool.Update(elapseSeconds, realElapseSeconds);
|
||||
|
||||
ProcessHeartBeat(realElapseSeconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理心跳
|
||||
/// </summary>
|
||||
/// <param name="realElapseSeconds"></param>
|
||||
private void ProcessHeartBeat(float realElapseSeconds)
|
||||
{
|
||||
if (PHeartBeatInterval > 0f)
|
||||
{
|
||||
bool sendHeartBeat = false;
|
||||
int missHeartBeatCount = 0;
|
||||
lock (PHeartBeatState)
|
||||
{
|
||||
if (PSocket == null || !PActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PHeartBeatState.HeartBeatElapseSeconds += realElapseSeconds;
|
||||
if (PHeartBeatState.HeartBeatElapseSeconds >= PHeartBeatInterval)
|
||||
{
|
||||
sendHeartBeat = true;
|
||||
missHeartBeatCount = PHeartBeatState.MissHeartBeatCount;
|
||||
PHeartBeatState.HeartBeatElapseSeconds = 0f;
|
||||
PHeartBeatState.MissHeartBeatCount++;
|
||||
}
|
||||
|
||||
if (sendHeartBeat && PNetworkChannelHelper.SendHeartBeat())
|
||||
{
|
||||
if (missHeartBeatCount > 0 && NetworkChannelMissHeartBeat != null)
|
||||
{
|
||||
NetworkChannelMissHeartBeat(this, missHeartBeatCount);
|
||||
}
|
||||
|
||||
// PHeartBeatState.Reset(this.ResetHeartBeatElapseSecondsWhenReceivePacket);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PHeartBeatState.MissHeartBeatCount > MissHeartBeatCountByClose)
|
||||
{
|
||||
// 心跳丢失达到上线。触发断开
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭网络频道。
|
||||
/// </summary>
|
||||
public virtual void Shutdown()
|
||||
{
|
||||
Close();
|
||||
PSendState.Reset();
|
||||
PReceivePacketPool.Shutdown();
|
||||
PNetworkChannelHelper.Shutdown();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 注册网络消息包处理函数。
|
||||
/// </summary>
|
||||
/// <param name="handler">要注册的网络消息包处理函数。</param>
|
||||
public void RegisterHandler(IPacketSendHeaderHandler handler)
|
||||
{
|
||||
GameFrameworkGuard.NotNull(handler, nameof(handler));
|
||||
_packetSendHeaderHandler = handler;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 注册网络消息包处理函数。
|
||||
/// </summary>
|
||||
/// <param name="handler">要注册的网络消息包处理函数。</param>
|
||||
public void RegisterHandler(IPacketSendBodyHandler handler)
|
||||
{
|
||||
GameFrameworkGuard.NotNull(handler, nameof(handler));
|
||||
_packetSendBodyHandler = handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册网络消息包处理函数。
|
||||
/// </summary>
|
||||
/// <param name="handler">要注册的网络消息包处理函数。</param>
|
||||
public void RegisterHandler(IPacketReceiveHeaderHandler handler)
|
||||
{
|
||||
GameFrameworkGuard.NotNull(handler, nameof(handler));
|
||||
_packetReceiveHeaderHandler = handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册网络消息包处理函数。
|
||||
/// </summary>
|
||||
/// <param name="handler">要注册的网络消息包处理函数。</param>
|
||||
public void RegisterHandler(IPacketReceiveBodyHandler handler)
|
||||
{
|
||||
GameFrameworkGuard.NotNull(handler, nameof(handler));
|
||||
_packetReceiveBodyHandler = handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册网络消息心跳处理函数,用于处理心跳消息
|
||||
/// </summary>
|
||||
/// <param name="handler">要注册的网络消息包处理函数</param>
|
||||
public void RegisterHandler(IPacketHeartBeatHandler handler)
|
||||
{
|
||||
GameFrameworkGuard.NotNull(handler, nameof(handler));
|
||||
_packetHeartBeatHandler = handler;
|
||||
if (handler.HeartBeatInterval > 0)
|
||||
{
|
||||
PHeartBeatInterval = handler.HeartBeatInterval;
|
||||
}
|
||||
|
||||
if (handler.MissHeartBeatCountByClose > 0)
|
||||
{
|
||||
MissHeartBeatCountByClose = handler.MissHeartBeatCountByClose;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置默认事件处理函数。
|
||||
/// </summary>
|
||||
/// <param name="handler">要设置的默认事件处理函数。</param>
|
||||
public void SetDefaultHandler(EventHandler<Packet> handler)
|
||||
{
|
||||
GameFrameworkGuard.NotNull(handler, nameof(handler));
|
||||
PReceivePacketPool.SetDefaultHandler(handler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接到远程主机。
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">远程主机的 IP 地址。</param>
|
||||
/// <param name="port">远程主机的端口号。</param>
|
||||
/// <param name="userData">用户自定义数据。</param>
|
||||
public virtual void Connect(IPAddress ipAddress, int port, object userData = null)
|
||||
{
|
||||
if (PSocket != null)
|
||||
{
|
||||
Close();
|
||||
PSocket = null;
|
||||
}
|
||||
|
||||
switch (ipAddress.AddressFamily)
|
||||
{
|
||||
case System.Net.Sockets.AddressFamily.InterNetwork:
|
||||
PAddressFamily = AddressFamily.IPv4;
|
||||
break;
|
||||
|
||||
case System.Net.Sockets.AddressFamily.InterNetworkV6:
|
||||
PAddressFamily = AddressFamily.IPv6;
|
||||
break;
|
||||
|
||||
default:
|
||||
string errorMessage = Utility.Text.Format("Not supported address family '{0}'.", ipAddress.AddressFamily);
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.AddressFamilyError, SocketError.Success, errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
PSendState.Reset();
|
||||
PReceiveState.PrepareForPacketHeader(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭连接并释放所有相关资源。
|
||||
/// </summary>
|
||||
public virtual void Close()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (PSocket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PActive = false;
|
||||
|
||||
try
|
||||
{
|
||||
PSocket.Shutdown();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
PSocket.Close();
|
||||
PSocket = null;
|
||||
|
||||
if (NetworkChannelClosed != null)
|
||||
{
|
||||
NetworkChannelClosed(this);
|
||||
}
|
||||
}
|
||||
|
||||
PSentPacketCount = 0;
|
||||
PReceivedPacketCount = 0;
|
||||
|
||||
lock (PSendPacketPool)
|
||||
{
|
||||
PSendPacketPool.Clear();
|
||||
}
|
||||
|
||||
PReceivePacketPool.Clear();
|
||||
|
||||
lock (PHeartBeatState)
|
||||
{
|
||||
PHeartBeatState.Reset(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 向远程主机发送消息包。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">消息包类型。</typeparam>
|
||||
/// <param name="messageObject">要发送的消息包。</param>
|
||||
public void Send<T>(T messageObject) where T : MessageObject
|
||||
{
|
||||
if (PSocket == null)
|
||||
{
|
||||
const string errorMessage = "You must connect first.";
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
if (!PActive)
|
||||
{
|
||||
const string errorMessage = "Socket is not active.";
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
if (messageObject == null)
|
||||
{
|
||||
const string errorMessage = "Packet is invalid.";
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
lock (PSendPacketPool)
|
||||
{
|
||||
PSendPacketPool.Enqueue(messageObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源。
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">释放资源标记。</param>
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
Close();
|
||||
PSendState.Dispose();
|
||||
PReceiveState.Dispose();
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理发送消息对象
|
||||
/// </summary>
|
||||
/// <param name="messageObject">消息对象</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
protected virtual bool ProcessSendMessage(MessageObject messageObject)
|
||||
{
|
||||
bool serializeResult = PNetworkChannelHelper.SerializePacketHeader(messageObject, PSendState.Stream, out var messageBodyBuffer);
|
||||
if (serializeResult)
|
||||
{
|
||||
serializeResult = PNetworkChannelHelper.SerializePacketBody(messageBodyBuffer, PSendState.Stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
const string errorMessage = "Serialized packet failure.";
|
||||
throw new InvalidOperationException(errorMessage);
|
||||
}
|
||||
|
||||
return serializeResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理消息发送
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="GameFrameworkException"></exception>
|
||||
protected virtual bool ProcessSend()
|
||||
{
|
||||
lock (PSendPacketPool)
|
||||
{
|
||||
if (PSendState.Stream.Length > 0 || PSendPacketPool.Count <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
while (PSendPacketPool.Count > 0)
|
||||
{
|
||||
var messageObject = PSendPacketPool.Dequeue();
|
||||
|
||||
bool serializeResult = false;
|
||||
try
|
||||
{
|
||||
serializeResult = ProcessSendMessage(messageObject);
|
||||
#if UNITY_EDITOR
|
||||
Log.Debug($"发送消息 ID:[{PacketSendHeaderHandler.Id}] ==>消息类型:{messageObject.GetType()} 消息内容:{Utility.Json.ToJson(messageObject)}");
|
||||
#endif
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
PActive = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.SerializeError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
if (!serializeResult)
|
||||
{
|
||||
const string errorMessage = "Serialized packet failure.";
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.SerializeError, SocketError.Success, errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
PSendState.Stream.SetLength(0);
|
||||
}
|
||||
|
||||
PSendState.Stream.Position = 0L;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ProcessReceive()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// 处理发送消息对象
|
||||
/// </summary>
|
||||
/// <param name="messageObject">消息对象</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
protected virtual bool ProcessReceiveMessage(MessageObject messageObject)
|
||||
{
|
||||
bool serializeResult = PNetworkChannelHelper.SerializePacketHeader(messageObject, PSendState.Stream, out var messageBodyBuffer);
|
||||
if (serializeResult)
|
||||
{
|
||||
serializeResult = PNetworkChannelHelper.SerializePacketBody(messageBodyBuffer, PSendState.Stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
const string errorMessage = "Serialized packet failure.";
|
||||
throw new InvalidOperationException(errorMessage);
|
||||
}
|
||||
|
||||
return serializeResult;
|
||||
}*/
|
||||
|
||||
protected virtual bool ProcessPacketHeader()
|
||||
{
|
||||
try
|
||||
{
|
||||
// var packetHeader = PNetworkChannelHelper.DeserializePacketHeader(PReceiveState.Stream, out var customErrorData);
|
||||
//
|
||||
// if (customErrorData != null && NetworkChannelCustomError != null)
|
||||
// {
|
||||
// NetworkChannelCustomError(this, customErrorData);
|
||||
// }
|
||||
//
|
||||
// if (packetHeader == null)
|
||||
// {
|
||||
// string errorMessage = "Packet header is invalid.";
|
||||
// if (NetworkChannelError != null)
|
||||
// {
|
||||
// NetworkChannelError(this, NetworkErrorCode.DeserializePacketHeaderError, SocketError.Success, errorMessage);
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// throw new GameFrameworkException(errorMessage);
|
||||
// }
|
||||
//
|
||||
// PReceiveState.PrepareForPacket(PacketReceiveHeaderHandler, PacketReceiveBodyHandler);
|
||||
// if (packetHeader.PacketLength <= 0)
|
||||
// {
|
||||
// bool processSuccess = ProcessPacket();
|
||||
// PReceivedPacketCount++;
|
||||
// return processSuccess;
|
||||
// }
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
PActive = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.DeserializePacketHeaderError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual bool ProcessPacket()
|
||||
{
|
||||
lock (PHeartBeatState)
|
||||
{
|
||||
PHeartBeatState.Reset(PResetHeartBeatElapseSecondsWhenReceivePacket);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var packet = PNetworkChannelHelper.DeserializePacketBody(PReceiveState.Stream, 0, out var customErrorData);
|
||||
|
||||
if (customErrorData != null && NetworkChannelCustomError != null)
|
||||
{
|
||||
NetworkChannelCustomError(this, customErrorData);
|
||||
}
|
||||
|
||||
if (packet)
|
||||
{
|
||||
PReceivePacketPool.Fire(this, null);
|
||||
}
|
||||
|
||||
PReceiveState.PrepareForPacketHeader(0);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
PActive = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.DeserializePacketError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8eb9cef7207c44569ba604eeb5d32899
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,105 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public sealed partial class NetworkManager
|
||||
{
|
||||
public sealed class ReceiveState : IDisposable
|
||||
{
|
||||
private const int DefaultBufferLength = 1024 * 64;
|
||||
private MemoryStream _mStream;
|
||||
private IPacketReceiveHeaderHandler _packetReceiveHeaderHandler;
|
||||
private IPacketReceiveBodyHandler _packetReceiveBodyHandler;
|
||||
private bool _disposed;
|
||||
|
||||
public ReceiveState()
|
||||
{
|
||||
_mStream = new MemoryStream(DefaultBufferLength);
|
||||
_packetReceiveHeaderHandler = null;
|
||||
_packetReceiveBodyHandler = null;
|
||||
_disposed = false;
|
||||
}
|
||||
|
||||
public MemoryStream Stream
|
||||
{
|
||||
get { return _mStream; }
|
||||
}
|
||||
|
||||
public IPacketReceiveHeaderHandler PacketHeaderHandler
|
||||
{
|
||||
get { return _packetReceiveHeaderHandler; }
|
||||
}
|
||||
|
||||
public IPacketReceiveBodyHandler PacketBodyHandler
|
||||
{
|
||||
get { return _packetReceiveBodyHandler; }
|
||||
}
|
||||
|
||||
public void PrepareForPacketHeader(int packetHeaderLength)
|
||||
{
|
||||
Reset(packetHeaderLength, null, null);
|
||||
}
|
||||
|
||||
public void PrepareForPacket(IPacketReceiveHeaderHandler packetHeader, IPacketReceiveBodyHandler packetBody)
|
||||
{
|
||||
if (packetHeader == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(packetHeader), "Packet header is invalid.");
|
||||
}
|
||||
|
||||
if (packetBody == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(packetBody), "Packet body is invalid.");
|
||||
}
|
||||
|
||||
Reset(packetHeader.PacketLength, packetHeader, packetBody);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
if (_mStream != null)
|
||||
{
|
||||
_mStream.Dispose();
|
||||
_mStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
private void Reset(int targetLength, IPacketReceiveHeaderHandler packetReceiveHeaderHandler, IPacketReceiveBodyHandler packetReceiveBodyHandler)
|
||||
{
|
||||
if (targetLength < 0)
|
||||
{
|
||||
throw new GameFrameworkException("Target length is invalid.");
|
||||
}
|
||||
|
||||
_mStream.Position = 0L;
|
||||
_mStream.SetLength(targetLength);
|
||||
_packetReceiveHeaderHandler = packetReceiveHeaderHandler;
|
||||
_packetReceiveBodyHandler = packetReceiveBodyHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d8f189af0c3b40328bec4eff82a654b7
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,64 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public sealed partial class NetworkManager
|
||||
{
|
||||
public sealed class SendState : IDisposable
|
||||
{
|
||||
private const int DefaultBufferLength = 1024 * 64;
|
||||
private MemoryStream _stream;
|
||||
private bool _disposed;
|
||||
|
||||
public SendState()
|
||||
{
|
||||
_stream = new MemoryStream(DefaultBufferLength);
|
||||
_disposed = false;
|
||||
}
|
||||
|
||||
public MemoryStream Stream
|
||||
{
|
||||
get { return _stream; }
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_stream.Position = 0L;
|
||||
_stream.SetLength(0L);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
if (_stream != null)
|
||||
{
|
||||
_stream.Dispose();
|
||||
_stream = null;
|
||||
}
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ca29f173c8354c0a829aa16e1dca3430
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,109 @@
|
|||
/*using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public partial class NetworkManager
|
||||
{
|
||||
private sealed class SystemNetSocket : INetworkSocket
|
||||
{
|
||||
private readonly Socket _socket;
|
||||
|
||||
|
||||
public SystemNetSocket(System.Net.Sockets.AddressFamily ipAddressAddressFamily, SocketType socketType, ProtocolType protocolType)
|
||||
{
|
||||
_socket = new Socket(ipAddressAddressFamily, socketType, protocolType);
|
||||
}
|
||||
|
||||
public bool IsConnected
|
||||
{
|
||||
get { return _socket.Connected; }
|
||||
}
|
||||
|
||||
public Socket Socket
|
||||
{
|
||||
get { return _socket; }
|
||||
}
|
||||
|
||||
public EndPoint LocalEndPoint
|
||||
{
|
||||
get { return _socket.LocalEndPoint; }
|
||||
}
|
||||
|
||||
public EndPoint RemoteEndPoint
|
||||
{
|
||||
get { return _socket.RemoteEndPoint; }
|
||||
}
|
||||
|
||||
public int Available
|
||||
{
|
||||
get { return _socket.Available; }
|
||||
}
|
||||
|
||||
public int ReceiveBufferSize
|
||||
{
|
||||
get { return _socket.ReceiveBufferSize; }
|
||||
set
|
||||
{
|
||||
if (value <= 0)
|
||||
{
|
||||
throw new ArgumentException("Receive buffer size is invalid.", nameof(value));
|
||||
}
|
||||
|
||||
_socket.ReceiveBufferSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int SendBufferSize
|
||||
{
|
||||
get { return _socket.SendBufferSize; }
|
||||
set
|
||||
{
|
||||
if (value <= 0)
|
||||
{
|
||||
throw new ArgumentException("Send buffer size is invalid.", nameof(value));
|
||||
}
|
||||
|
||||
_socket.SendBufferSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
_socket.Shutdown(SocketShutdown.Both);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_socket.Close();
|
||||
}
|
||||
|
||||
|
||||
public void BeginSend(byte[] getBuffer, int streamPosition, int streamLength, SocketFlags none, AsyncCallback mSendCallback, INetworkSocket mSocket)
|
||||
{
|
||||
_socket.BeginSend(getBuffer, streamPosition, streamLength, none, mSendCallback, mSocket);
|
||||
}
|
||||
|
||||
public void BeginReceive(byte[] getBuffer, int streamPosition, int streamLength, SocketFlags none, AsyncCallback mReceiveCallback, INetworkSocket mSocket)
|
||||
{
|
||||
_socket.BeginReceive(getBuffer, streamPosition, streamLength, none, mReceiveCallback, mSocket);
|
||||
}
|
||||
|
||||
public void BeginConnect(IPAddress ipAddress, int port, AsyncCallback mConnectCallback, ConnectState connectState)
|
||||
{
|
||||
_socket.BeginConnect(ipAddress, port, mConnectCallback, connectState);
|
||||
}
|
||||
|
||||
public void EndConnect(IAsyncResult ar)
|
||||
{
|
||||
_socket.EndConnect(ar);
|
||||
}
|
||||
|
||||
public int Receive(byte[] getBuffer, int streamPosition, int streamLength, SocketFlags none)
|
||||
{
|
||||
return _socket.Receive(getBuffer, streamPosition, streamLength, none);
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a97b60f62dc6440f88f8bc6e6b0cbd12
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,279 @@
|
|||
/*//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public sealed partial class NetworkManager
|
||||
{
|
||||
/// <summary>
|
||||
/// TCP 网络频道。
|
||||
/// </summary>
|
||||
private sealed class TcpNetworkChannel : NetworkChannelBase
|
||||
{
|
||||
private readonly AsyncCallback _connectCallback;
|
||||
private readonly AsyncCallback _sendCallback;
|
||||
private readonly AsyncCallback _receiveCallback;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络频道的新实例。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
||||
public TcpNetworkChannel(string name, INetworkChannelHelper networkChannelHelper)
|
||||
: base(name, networkChannelHelper)
|
||||
{
|
||||
_connectCallback = ConnectCallback;
|
||||
_sendCallback = SendCallback;
|
||||
_receiveCallback = ReceiveCallback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接到远程主机。
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">远程主机的 IP 地址。</param>
|
||||
/// <param name="port">远程主机的端口号。</param>
|
||||
/// <param name="userData">用户自定义数据。</param>
|
||||
public override void Connect(IPAddress ipAddress, int port, object userData = null)
|
||||
{
|
||||
base.Connect(ipAddress, port, userData);
|
||||
PSocket = new SystemNetSocket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
if (PSocket == null)
|
||||
{
|
||||
string errorMessage = "Initialize network channel failure.";
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.SocketError, SocketError.Success, errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
PNetworkChannelHelper.PrepareForConnecting();
|
||||
ConnectAsync(ipAddress, port, userData);
|
||||
}
|
||||
|
||||
protected override bool ProcessSend()
|
||||
{
|
||||
if (base.ProcessSend())
|
||||
{
|
||||
SendAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ConnectAsync(IPAddress ipAddress, int port, object userData)
|
||||
{
|
||||
try
|
||||
{
|
||||
((SystemNetSocket)PSocket).BeginConnect(ipAddress, port, _connectCallback, new ConnectState(PSocket, userData));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.ConnectError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectCallback(IAsyncResult ar)
|
||||
{
|
||||
ConnectState socketUserData = (ConnectState)ar.AsyncState;
|
||||
try
|
||||
{
|
||||
((SystemNetSocket)socketUserData.Socket).EndConnect(ar);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
PActive = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.ConnectError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
PSentPacketCount = 0;
|
||||
PReceivedPacketCount = 0;
|
||||
|
||||
lock (PSendPacketPool)
|
||||
{
|
||||
PSendPacketPool.Clear();
|
||||
}
|
||||
|
||||
PReceivePacketPool.Clear();
|
||||
|
||||
lock (PHeartBeatState)
|
||||
{
|
||||
PHeartBeatState.Reset(true);
|
||||
}
|
||||
|
||||
if (NetworkChannelConnected != null)
|
||||
{
|
||||
NetworkChannelConnected(this, socketUserData.UserData);
|
||||
}
|
||||
|
||||
PActive = true;
|
||||
ReceiveAsync();
|
||||
}
|
||||
|
||||
private void SendAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
((SystemNetSocket)PSocket).BeginSend(PSendState.Stream.GetBuffer(), (int)PSendState.Stream.Position, (int)(PSendState.Stream.Length - PSendState.Stream.Position), SocketFlags.None, _sendCallback, PSocket);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
PActive = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.SendError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void SendCallback(IAsyncResult ar)
|
||||
{
|
||||
Socket socket = ((SystemNetSocket)ar.AsyncState).Socket;
|
||||
if (!socket.Connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int bytesSent = 0;
|
||||
try
|
||||
{
|
||||
bytesSent = socket.EndSend(ar);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
PActive = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.SendError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
PSendState.Stream.Position += bytesSent;
|
||||
if (PSendState.Stream.Position < PSendState.Stream.Length)
|
||||
{
|
||||
SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
PSentPacketCount++;
|
||||
PSendState.Reset();
|
||||
}
|
||||
|
||||
private void ReceiveAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
((SystemNetSocket)PSocket).BeginReceive(PReceiveState.Stream.GetBuffer(), (int)PReceiveState.Stream.Position, (int)(PReceiveState.Stream.Length - PReceiveState.Stream.Position), SocketFlags.None, _receiveCallback, PSocket);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
PActive = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.ReceiveError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReceiveCallback(IAsyncResult ar)
|
||||
{
|
||||
Socket socket = ((INetworkSocket)ar.AsyncState).Socket;
|
||||
if (!socket.Connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int bytesReceived = 0;
|
||||
try
|
||||
{
|
||||
bytesReceived = socket.EndReceive(ar);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
PActive = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.ReceiveError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
if (bytesReceived <= 0)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
PReceiveState.Stream.Position += bytesReceived;
|
||||
if (PReceiveState.Stream.Position < PReceiveState.Stream.Length)
|
||||
{
|
||||
ReceiveAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
PReceiveState.Stream.Position = 0L;
|
||||
|
||||
bool processSuccess = false;
|
||||
if (PReceiveState.PacketHeaderHandler != null)
|
||||
{
|
||||
processSuccess = ProcessPacket();
|
||||
PReceivedPacketCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
processSuccess = ProcessPacketHeader();
|
||||
}
|
||||
|
||||
if (processSuccess)
|
||||
{
|
||||
ReceiveAsync();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3e1854e4c28b4ade9bb03f60cda5d650
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,99 @@
|
|||
#if ENABLE_GAME_FRAME_X_WEB_SOCKET
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using UnityWebSocket;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public partial class NetworkManager
|
||||
{
|
||||
private sealed class WebSocketClientNetSocket : INetworkSocket
|
||||
{
|
||||
private readonly IWebSocket _client;
|
||||
|
||||
/// <summary>
|
||||
/// 是否是加密协议
|
||||
/// </summary>
|
||||
private readonly bool IsSSL = false;
|
||||
|
||||
TaskCompletionSource<bool> _connectTask = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
private Action<byte[]> _action;
|
||||
|
||||
public WebSocketClientNetSocket(IPAddress ipAddress, int port, Action<byte[]> action)
|
||||
{
|
||||
_client = new WebSocket("ws://" + ipAddress + ":" + port + "/" + (IsSSL ? "wss" : "ws"));
|
||||
_action = action;
|
||||
_client.OnOpen += OnOpen;
|
||||
_client.OnError += OnError;
|
||||
_client.OnClose += OnClose;
|
||||
_client.OnMessage += OnMessage;
|
||||
}
|
||||
|
||||
private void OnMessage(object sender, MessageEventArgs e)
|
||||
{
|
||||
if (e.IsBinary)
|
||||
{
|
||||
_action.Invoke(e.RawData);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClose(object sender, CloseEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
private void OnError(object sender, ErrorEventArgs e)
|
||||
{
|
||||
_connectTask.TrySetResult(false);
|
||||
}
|
||||
|
||||
private void OnOpen(object sender, OpenEventArgs e)
|
||||
{
|
||||
_connectTask.TrySetResult(true);
|
||||
}
|
||||
|
||||
|
||||
public async Task ConnectAsync()
|
||||
{
|
||||
_connectTask = new TaskCompletionSource<bool>();
|
||||
_client.ConnectAsync();
|
||||
await _connectTask.Task;
|
||||
}
|
||||
|
||||
public IWebSocket Client
|
||||
{
|
||||
get { return _client; }
|
||||
}
|
||||
|
||||
public bool IsConnected
|
||||
{
|
||||
get { return _client.IsConnected; }
|
||||
}
|
||||
|
||||
public EndPoint LocalEndPoint
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public EndPoint RemoteEndPoint
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public int ReceiveBufferSize { get; set; }
|
||||
public int SendBufferSize { get; set; }
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
_client.CloseAsync();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_client.CloseAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7fca9918ccef459e80f58cee2259ceac
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,289 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
#if ENABLE_GAME_FRAME_X_WEB_SOCKET
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using GameFrameX.Runtime;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public sealed partial class NetworkManager
|
||||
{
|
||||
/// <summary>
|
||||
/// TCP 网络频道。
|
||||
/// </summary>
|
||||
private sealed class WebSocketNetworkChannel : NetworkChannelBase
|
||||
{
|
||||
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络频道的新实例。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
||||
public WebSocketNetworkChannel(string name, INetworkChannelHelper networkChannelHelper)
|
||||
: base(name, networkChannelHelper)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接到远程主机。
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">远程主机的 IP 地址。</param>
|
||||
/// <param name="port">远程主机的端口号。</param>
|
||||
/// <param name="userData">用户自定义数据。</param>
|
||||
public override void Connect(IPAddress ipAddress, int port, object userData = null)
|
||||
{
|
||||
base.Connect(ipAddress, port, userData);
|
||||
PSocket = new WebSocketClientNetSocket(ipAddress, port, ReceiveCallback);
|
||||
if (PSocket == null)
|
||||
{
|
||||
const string errorMessage = "Initialize network channel failure.";
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.SocketError, SocketError.Success, errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
PNetworkChannelHelper.PrepareForConnecting();
|
||||
ConnectAsync(userData);
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
_cancellationTokenSource.Cancel();
|
||||
}
|
||||
|
||||
private bool IsClose()
|
||||
{
|
||||
return _cancellationTokenSource.IsCancellationRequested;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 处理发送消息对象
|
||||
/// </summary>
|
||||
/// <param name="messageObject">消息对象</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
protected override bool ProcessSendMessage(MessageObject messageObject)
|
||||
{
|
||||
if (IsClose())
|
||||
{
|
||||
PActive = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.SocketError, SocketError.Disconnecting, "Network channel is closing.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool serializeResult = base.ProcessSendMessage(messageObject);
|
||||
if (serializeResult)
|
||||
{
|
||||
// TODO 效率不高
|
||||
var tcpClientNetSocket = (WebSocketClientNetSocket)PSocket;
|
||||
|
||||
byte[] buffer = new byte[PSendState.Stream.Length];
|
||||
PSendState.Stream.Seek(0, SeekOrigin.Begin);
|
||||
_ = PSendState.Stream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
tcpClientNetSocket.Client.SendAsync(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
const string errorMessage = "Serialized packet failure.";
|
||||
throw new InvalidOperationException(errorMessage);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async void ConnectAsync(object userData)
|
||||
{
|
||||
try
|
||||
{
|
||||
var socketClient = (WebSocketClientNetSocket)PSocket;
|
||||
await socketClient.ConnectAsync();
|
||||
ConnectCallback(new ConnectState(PSocket, userData));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.ConnectError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ConnectCallback(ConnectState connectState)
|
||||
{
|
||||
try
|
||||
{
|
||||
var socketUserData = (WebSocketClientNetSocket)PSocket;
|
||||
if (!socketUserData.IsConnected)
|
||||
{
|
||||
throw new SocketException((int)NetworkErrorCode.ConnectError);
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
PActive = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.ConnectError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
PSentPacketCount = 0;
|
||||
PReceivedPacketCount = 0;
|
||||
|
||||
lock (PSendPacketPool)
|
||||
{
|
||||
PSendPacketPool.Clear();
|
||||
}
|
||||
|
||||
PReceivePacketPool.Clear();
|
||||
|
||||
lock (PHeartBeatState)
|
||||
{
|
||||
PHeartBeatState.Reset(true);
|
||||
}
|
||||
|
||||
if (NetworkChannelConnected != null)
|
||||
{
|
||||
NetworkChannelConnected(this, connectState.UserData);
|
||||
}
|
||||
|
||||
PActive = true;
|
||||
}
|
||||
|
||||
private async void ReceiveCallback(byte[] buffer)
|
||||
{
|
||||
// PReceiveState.Stream.Seek(0, SeekOrigin.Begin);
|
||||
// PReceiveState.Stream.Write(buffer, 0, buffer.Length);
|
||||
// if (PReceiveState.Stream.Position < PReceiveState.Stream.Length)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// PReceiveState.Stream.Position = 0L;
|
||||
|
||||
ProcessReceiveMessage(ref buffer);
|
||||
// bool processSuccess = false;
|
||||
// if (PReceiveState.PacketHeaderHandler != null)
|
||||
// {
|
||||
// processSuccess = ProcessPacket();
|
||||
// PReceivedPacketCount++;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// processSuccess = ProcessPacketHeader();
|
||||
// }
|
||||
}
|
||||
|
||||
private bool ProcessReceiveMessage(ref byte[] buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (PHeartBeatState)
|
||||
{
|
||||
PHeartBeatState.Reset(PResetHeartBeatElapseSecondsWhenReceivePacket);
|
||||
}
|
||||
|
||||
PReceivedPacketCount++;
|
||||
|
||||
if (buffer.Length < PacketReceiveHeaderHandler.PacketHeaderLength)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// var header = buffer.Slice(buffer.Start, PacketReceiveHeaderHandler.PacketHeaderLength);
|
||||
// buffer = buffer.Slice(PacketReceiveHeaderHandler.PacketHeaderLength);
|
||||
var result = PNetworkChannelHelper.DeserializePacketHeader(buffer);
|
||||
if (result)
|
||||
{
|
||||
var bodyLength = PacketReceiveHeaderHandler.PacketLength - PacketReceiveHeaderHandler.PacketHeaderLength;
|
||||
if (buffer.Length < bodyLength)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var body = new byte[bodyLength - 4];
|
||||
|
||||
Array.Copy(buffer, PacketReceiveHeaderHandler.PacketHeaderLength, body, 0, bodyLength-4); //buffer.Slice(buffer.Start, bodyLength);
|
||||
// var bodyFirst = body.First.ToArray();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
// foreach (byte b in bodyFirst)
|
||||
// {
|
||||
// stringBuilder.Append(b + " ");
|
||||
// }
|
||||
|
||||
// buffer = buffer.Slice(bodyLength);
|
||||
result = PNetworkChannelHelper.DeserializePacketBody(body, PacketReceiveHeaderHandler.Id, out var messageObject);
|
||||
#if UNITY_EDITOR
|
||||
Log.Debug($"收到消息 ID:[{PacketReceiveHeaderHandler.Id}] ==>消息类型:{messageObject.GetType()} 消息内容:{Utility.Json.ToJson(messageObject)}");
|
||||
#endif
|
||||
if (!result)
|
||||
{
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.DeserializePacketError, SocketError.Success, "Packet body is invalid.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PacketBase packetBase = ReferencePool.Acquire<PacketBase>();
|
||||
packetBase.MessageObject = messageObject;
|
||||
packetBase.MessageId = PacketReceiveHeaderHandler.Id;
|
||||
PReceivePacketPool.Fire(this, packetBase);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.DeserializePacketHeaderError, SocketError.Success, "Packet header is invalid.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8de67fed18384b41a07efc1737296356
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,295 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络管理器。
|
||||
/// </summary>
|
||||
public sealed partial class NetworkManager : GameFrameworkModule, INetworkManager
|
||||
{
|
||||
private readonly Dictionary<string, NetworkChannelBase> m_NetworkChannels;
|
||||
|
||||
private EventHandler<NetworkConnectedEventArgs> m_NetworkConnectedEventHandler;
|
||||
private EventHandler<NetworkClosedEventArgs> m_NetworkClosedEventHandler;
|
||||
private EventHandler<NetworkMissHeartBeatEventArgs> m_NetworkMissHeartBeatEventHandler;
|
||||
private EventHandler<NetworkErrorEventArgs> m_NetworkErrorEventHandler;
|
||||
private EventHandler<NetworkCustomErrorEventArgs> m_NetworkCustomErrorEventHandler;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络管理器的新实例。
|
||||
/// </summary>
|
||||
public NetworkManager()
|
||||
{
|
||||
m_NetworkChannels = new Dictionary<string, NetworkChannelBase>(StringComparer.Ordinal);
|
||||
m_NetworkConnectedEventHandler = null;
|
||||
m_NetworkClosedEventHandler = null;
|
||||
m_NetworkMissHeartBeatEventHandler = null;
|
||||
m_NetworkErrorEventHandler = null;
|
||||
m_NetworkCustomErrorEventHandler = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道数量。
|
||||
/// </summary>
|
||||
public int NetworkChannelCount => m_NetworkChannels.Count;
|
||||
|
||||
/// <summary>
|
||||
/// 网络连接成功事件。
|
||||
/// </summary>
|
||||
public event EventHandler<NetworkConnectedEventArgs> NetworkConnected
|
||||
{
|
||||
add => m_NetworkConnectedEventHandler += value;
|
||||
remove => m_NetworkConnectedEventHandler -= value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 网络连接关闭事件。
|
||||
/// </summary>
|
||||
public event EventHandler<NetworkClosedEventArgs> NetworkClosed
|
||||
{
|
||||
add => m_NetworkClosedEventHandler += value;
|
||||
remove => m_NetworkClosedEventHandler -= value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 网络心跳包丢失事件。
|
||||
/// </summary>
|
||||
public event EventHandler<NetworkMissHeartBeatEventArgs> NetworkMissHeartBeat
|
||||
{
|
||||
add => m_NetworkMissHeartBeatEventHandler += value;
|
||||
remove => m_NetworkMissHeartBeatEventHandler -= value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 网络错误事件。
|
||||
/// </summary>
|
||||
public event EventHandler<NetworkErrorEventArgs> NetworkError
|
||||
{
|
||||
add => m_NetworkErrorEventHandler += value;
|
||||
remove => m_NetworkErrorEventHandler -= value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户自定义网络错误事件。
|
||||
/// </summary>
|
||||
public event EventHandler<NetworkCustomErrorEventArgs> NetworkCustomError
|
||||
{
|
||||
add => m_NetworkCustomErrorEventHandler += value;
|
||||
remove => m_NetworkCustomErrorEventHandler -= value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 网络管理器轮询。
|
||||
/// </summary>
|
||||
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
|
||||
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
|
||||
protected override void Update(float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
foreach (var networkChannel in m_NetworkChannels)
|
||||
{
|
||||
networkChannel.Value.Update(elapseSeconds, realElapseSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭并清理网络管理器。
|
||||
/// </summary>
|
||||
protected override void Shutdown()
|
||||
{
|
||||
foreach (var networkChannel in m_NetworkChannels)
|
||||
{
|
||||
NetworkChannelBase networkChannelBase = networkChannel.Value;
|
||||
networkChannelBase.NetworkChannelConnected -= OnNetworkChannelConnected;
|
||||
networkChannelBase.NetworkChannelClosed -= OnNetworkChannelClosed;
|
||||
networkChannelBase.NetworkChannelMissHeartBeat -= OnNetworkChannelMissHeartBeat;
|
||||
networkChannelBase.NetworkChannelError -= OnNetworkChannelError;
|
||||
networkChannelBase.NetworkChannelCustomError -= OnNetworkChannelCustomError;
|
||||
networkChannelBase.Shutdown();
|
||||
}
|
||||
|
||||
m_NetworkChannels.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否存在网络频道。
|
||||
/// </summary>
|
||||
/// <param name="channelName">网络频道名称。</param>
|
||||
/// <returns>是否存在网络频道。</returns>
|
||||
public bool HasNetworkChannel(string channelName)
|
||||
{
|
||||
return m_NetworkChannels.ContainsKey(channelName ?? string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道。
|
||||
/// </summary>
|
||||
/// <param name="channelName">网络频道名称。</param>
|
||||
/// <returns>要获取的网络频道。</returns>
|
||||
public INetworkChannel GetNetworkChannel(string channelName)
|
||||
{
|
||||
if (m_NetworkChannels.TryGetValue(channelName ?? string.Empty, out var networkChannel))
|
||||
{
|
||||
return networkChannel;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有网络频道。
|
||||
/// </summary>
|
||||
/// <returns>所有网络频道。</returns>
|
||||
public INetworkChannel[] GetAllNetworkChannels()
|
||||
{
|
||||
var index = 0;
|
||||
var results = new INetworkChannel[m_NetworkChannels.Count];
|
||||
foreach (var networkChannel in m_NetworkChannels)
|
||||
{
|
||||
results[index++] = networkChannel.Value;
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有网络频道。
|
||||
/// </summary>
|
||||
/// <param name="results">所有网络频道。</param>
|
||||
public void GetAllNetworkChannels(List<INetworkChannel> results)
|
||||
{
|
||||
GameFrameworkGuard.NotNull(results, nameof(results));
|
||||
|
||||
results.Clear();
|
||||
foreach (var networkChannel in m_NetworkChannels)
|
||||
{
|
||||
results.Add(networkChannel.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建网络频道。
|
||||
/// </summary>
|
||||
/// <param name="channelName">网络频道名称。</param>
|
||||
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
||||
/// <returns>要创建的网络频道。</returns>
|
||||
public INetworkChannel CreateNetworkChannel(string channelName, INetworkChannelHelper networkChannelHelper)
|
||||
{
|
||||
GameFrameworkGuard.NotNull(networkChannelHelper, nameof(networkChannelHelper));
|
||||
|
||||
if (HasNetworkChannel(channelName))
|
||||
{
|
||||
throw new GameFrameworkException(Utility.Text.Format("Already exist network channel '{0}'.", channelName ?? string.Empty));
|
||||
}
|
||||
#if ENABLE_GAME_FRAME_X_WEB_SOCKET
|
||||
NetworkChannelBase networkChannel = new WebSocketNetworkChannel(channelName, networkChannelHelper);
|
||||
#else
|
||||
NetworkChannelBase networkChannel = new SocketNetworkChannel(channelName, networkChannelHelper);
|
||||
#endif
|
||||
networkChannel.NetworkChannelConnected += OnNetworkChannelConnected;
|
||||
networkChannel.NetworkChannelClosed += OnNetworkChannelClosed;
|
||||
networkChannel.NetworkChannelMissHeartBeat += OnNetworkChannelMissHeartBeat;
|
||||
networkChannel.NetworkChannelError += OnNetworkChannelError;
|
||||
networkChannel.NetworkChannelCustomError += OnNetworkChannelCustomError;
|
||||
m_NetworkChannels.Add(channelName, networkChannel);
|
||||
return networkChannel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销毁网络频道。
|
||||
/// </summary>
|
||||
/// <param name="channelName">网络频道名称。</param>
|
||||
/// <returns>是否销毁网络频道成功。</returns>
|
||||
public bool DestroyNetworkChannel(string channelName)
|
||||
{
|
||||
if (m_NetworkChannels.TryGetValue(channelName ?? string.Empty, out var networkChannel))
|
||||
{
|
||||
networkChannel.NetworkChannelConnected -= OnNetworkChannelConnected;
|
||||
networkChannel.NetworkChannelClosed -= OnNetworkChannelClosed;
|
||||
networkChannel.NetworkChannelMissHeartBeat -= OnNetworkChannelMissHeartBeat;
|
||||
networkChannel.NetworkChannelError -= OnNetworkChannelError;
|
||||
networkChannel.NetworkChannelCustomError -= OnNetworkChannelCustomError;
|
||||
networkChannel.Shutdown();
|
||||
if (channelName != null)
|
||||
{
|
||||
return m_NetworkChannels.Remove(channelName);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnNetworkChannelConnected(NetworkChannelBase networkChannel, object userData)
|
||||
{
|
||||
if (m_NetworkConnectedEventHandler != null)
|
||||
{
|
||||
lock (m_NetworkConnectedEventHandler)
|
||||
{
|
||||
NetworkConnectedEventArgs networkConnectedEventArgs = NetworkConnectedEventArgs.Create(networkChannel, userData);
|
||||
m_NetworkConnectedEventHandler(this, networkConnectedEventArgs);
|
||||
// ReferencePool.Release(networkConnectedEventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkChannelClosed(NetworkChannelBase networkChannel)
|
||||
{
|
||||
if (m_NetworkClosedEventHandler != null)
|
||||
{
|
||||
lock (m_NetworkClosedEventHandler)
|
||||
{
|
||||
NetworkClosedEventArgs networkClosedEventArgs = NetworkClosedEventArgs.Create(networkChannel);
|
||||
m_NetworkClosedEventHandler(this, networkClosedEventArgs);
|
||||
// ReferencePool.Release(networkClosedEventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkChannelMissHeartBeat(NetworkChannelBase networkChannel, int missHeartBeatCount)
|
||||
{
|
||||
if (m_NetworkMissHeartBeatEventHandler != null)
|
||||
{
|
||||
lock (m_NetworkMissHeartBeatEventHandler)
|
||||
{
|
||||
NetworkMissHeartBeatEventArgs networkMissHeartBeatEventArgs = NetworkMissHeartBeatEventArgs.Create(networkChannel, missHeartBeatCount);
|
||||
m_NetworkMissHeartBeatEventHandler(this, networkMissHeartBeatEventArgs);
|
||||
// ReferencePool.Release(networkMissHeartBeatEventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkChannelError(NetworkChannelBase networkChannel, NetworkErrorCode errorCode, SocketError socketErrorCode, string errorMessage)
|
||||
{
|
||||
if (m_NetworkErrorEventHandler != null)
|
||||
{
|
||||
lock (m_NetworkErrorEventHandler)
|
||||
{
|
||||
NetworkErrorEventArgs networkErrorEventArgs = NetworkErrorEventArgs.Create(networkChannel, errorCode, socketErrorCode, errorMessage);
|
||||
m_NetworkErrorEventHandler(this, networkErrorEventArgs);
|
||||
// ReferencePool.Release(networkErrorEventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkChannelCustomError(NetworkChannelBase networkChannel, object customErrorData)
|
||||
{
|
||||
if (m_NetworkCustomErrorEventHandler != null)
|
||||
{
|
||||
lock (m_NetworkCustomErrorEventHandler)
|
||||
{
|
||||
NetworkCustomErrorEventArgs networkCustomErrorEventArgs = NetworkCustomErrorEventArgs.Create(networkChannel, customErrorData);
|
||||
m_NetworkCustomErrorEventHandler(this, networkCustomErrorEventArgs);
|
||||
// ReferencePool.Release(networkCustomErrorEventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b730bf25813d4ea295e6a07d9985941c
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,17 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息包基类。
|
||||
/// </summary>
|
||||
public abstract class Packet : BaseEventArgs
|
||||
{
|
||||
// public abstract int PacketSize();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3c8aec49e4884375a94d4e9efbeb96b4
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,23 @@
|
|||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
public class PacketBase : Packet
|
||||
{
|
||||
public MessageObject MessageObject { get; set; }
|
||||
public int MessageId { get; set; }
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
MessageId = 0;
|
||||
}
|
||||
|
||||
public override string Id
|
||||
{
|
||||
get { return MessageId.ToString(); }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "Packet ID: " + MessageId + ", Message: " + MessageObject;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c7d814943d7941bc91b634f39730d506
|
||||
timeCreated: 1712727663
|
|
@ -0,0 +1,105 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace GameFrameX.Network.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 协议消息处理器
|
||||
/// </summary>
|
||||
public static class ProtoMessageIdHandler
|
||||
{
|
||||
private static readonly BidirectionalDictionary<int, Type> ReqDictionary = new BidirectionalDictionary<int, Type>();
|
||||
private static readonly BidirectionalDictionary<int, Type> RespDictionary = new BidirectionalDictionary<int, Type>();
|
||||
|
||||
/// <summary>
|
||||
/// 根据消息ID获取请求的类型
|
||||
/// </summary>
|
||||
/// <param name="messageId">消息ID</param>
|
||||
/// <returns>请求的类型</returns>
|
||||
public static Type GetReqTypeById(int messageId)
|
||||
{
|
||||
ReqDictionary.TryGetValue(messageId, out var value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据类型获取请求消息ID
|
||||
/// </summary>
|
||||
/// <param name="type">类型</param>
|
||||
/// <returns>请求消息ID</returns>
|
||||
public static int GetReqMessageIdByType(Type type)
|
||||
{
|
||||
ReqDictionary.TryGetKey(type, out var value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据消息ID获取响应的类型
|
||||
/// </summary>
|
||||
/// <param name="messageId">消息ID</param>
|
||||
/// <returns>响应的类型</returns>
|
||||
public static Type GetRespTypeById(int messageId)
|
||||
{
|
||||
RespDictionary.TryGetValue(messageId, out var value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据类型获取响应消息ID
|
||||
/// </summary>
|
||||
/// <param name="type">类型</param>
|
||||
/// <returns>响应消息ID</returns>
|
||||
public static int GetRespMessageIdByType(Type type)
|
||||
{
|
||||
RespDictionary.TryGetKey(type, out var value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化所有协议对象
|
||||
/// </summary>
|
||||
public static void Init(Assembly assembly)
|
||||
{
|
||||
ReqDictionary.Clear();
|
||||
RespDictionary.Clear();
|
||||
var types = assembly.GetTypes();
|
||||
StringBuilder stringBuilder = new StringBuilder(1024);
|
||||
foreach (var type in types)
|
||||
{
|
||||
var attribute = type.GetCustomAttribute(typeof(MessageTypeHandlerAttribute));
|
||||
if (attribute == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
stringBuilder.AppendLine(type.FullName);
|
||||
if (attribute is MessageTypeHandlerAttribute messageIdHandler)
|
||||
{
|
||||
if (type.IsImplWithInterface(typeof(IRequestMessage)))
|
||||
{
|
||||
// 请求
|
||||
if (!ReqDictionary.TryAdd(messageIdHandler.MessageId, type))
|
||||
{
|
||||
ReqDictionary.TryGetValue(messageIdHandler.MessageId, out var value);
|
||||
throw new GameFrameworkException($"请求Id重复==>当前ID:{messageIdHandler.MessageId},已有ID类型:{value.FullName}");
|
||||
}
|
||||
}
|
||||
else if (type.IsImplWithInterface(typeof(IResponseMessage)))
|
||||
{
|
||||
// 返回
|
||||
if (!RespDictionary.TryAdd(messageIdHandler.MessageId, type))
|
||||
{
|
||||
RespDictionary.TryGetValue(messageIdHandler.MessageId, out var value);
|
||||
throw new GameFrameworkException($"返回Id重复==>当前ID:{messageIdHandler.MessageId},已有ID类型:{value.FullName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameFrameworkLog.Debug(" 注册消息ID类型: " + stringBuilder);
|
||||
GameFrameworkLog.Info(" 注册消息ID类型: 结束");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9e5dff838bff4fdb84ed874cf3de295a
|
||||
timeCreated: 1712727663
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue