更新日期:2019年12月17日。
Github源码:​​​[点我获取源码]​​​ Gitee源码:​​[点我获取源码]​

索引

  • ​​Network网络客户端简介​​
  • ​​使用Network​​
  • ​​新建通信管道​​
  • ​​启用通信管道​​
  • ​​开始网络通信​​
  • ​​启动服务器​​
  • ​​启动客户端主场景​​
  • ​​连接服务器【面向连接型管道】​​
  • ​​发送消息并接受服务器返回消息【面向连接型管道】​​
  • ​​发送消息并接受服务器返回消息【非面向连接型管道】​​
  • ​​主动断开连接【面向连接型管道】​​
  • ​​关闭服务器​​
  • ​​扩展:关于心跳包机制和断线重连机制​​
  • ​​心跳包机制​​
  • ​​断线重连机制​​
  • ​​运行时检视面板​​

Network网络客户端简介

网络客户端模块,以单个通信管道为单位,每个管道均支持TCP/UDP等协议,可以为每个管道定义通信消息格式,基本能胜任一些常见的通信环境。

使用Network

新建通信管道

通信管道类,必须满足以下条件:
1.继承至ProtocolChannelBase

推荐使用快捷创建方式:

Project界面右键 -> Create -> HTFramework -> C# Protocol Channel Script

【Unity】 HTFramework框架(二十六)Network网络客户端_网络


如下,新建了一个通信管道:

public class NewTcpChannel : ProtocolChannelBase
{
/// <summary>
/// 通信协议
/// </summary>
public override ProtocolType Protocol
{
get
{
return ProtocolType.Tcp;
}
}
/// <summary>
/// 通道类型
/// </summary>
public override SocketType Way
{
get
{
return SocketType.Stream;
}
}
/// <summary>
/// 是否需要保持连接
/// </summary>
public override bool IsNeedConnect
{
get
{
return true;
}
}

/// <summary>
/// 是否是断开连接请求
/// </summary>
/// <param name="message">消息对象</param>
/// <returns>是否是断开连接请求</returns>
public override bool IsDisconnectRequest(INetworkMessage message)
{
return false;
}
/// <summary>
/// 封装消息
/// </summary>
/// <param name="message">消息对象</param>
/// <returns>封装后的字节数组</returns>
public override byte[] EncapsulatedMessage(INetworkMessage message)
{
return null;
}
/// <summary>
/// 接收消息
/// </summary>
/// <param name="client">客户端</param>
/// <returns>接收到的消息对象</returns>
protected override INetworkMessage ReceiveMessage(Socket client)
{
Thread.Sleep(5000);
return null;
}
}

ProtocolChannel详解:

1.Protocol属性指定了管道所使用的协议;

2.Way属性指定了管道的通信类型(一般情况面向连接的协议建议使用Stream,非面向连接的建议使用Dgram);

3.IsNeedConnect属性指定了通道是否面向连接;

4.IsDisconnectRequest方法做为一个评判标准,判定传入的参数INetworkMessage(通信消息接口)是否为断开连接的请求,你不需要做其他任何工作,只需要在这里指定此通道收到何种格式的消息时会断开与服务器的连接(面向连接型通道),断开连接后可以再次连接。

【例】在框架内置的TcpChannel通道中,当主次命令皆为-1时,则为终止连接的请求,服务器端也应是同样的规则:

/// <summary>
/// 是否是断开连接请求
/// </summary>
/// <param name="message">消息对象</param>
/// <returns>是否是断开连接请求</returns>
public override bool IsDisconnectRequest(INetworkMessage message)
{
//TcpNetworkInfo 框架内置的通信消息协议,一个通道仅可处理同一种协议的消息
TcpNetworkInfo networkInfo = message as TcpNetworkInfo;
if (networkInfo != null)
{
//Command 主命令,Subcommand 次命令
if (networkInfo.Command == -1 && networkInfo.Subcommand == -1)
{
return true;
}
}
return false;
}

5.EncapsulatedMessage决定此通道如何将消息对象INetworkMessage封装为可供网络传输的字节数组。

6.ReceiveMessage决定此通道如何从Socket缓存区中取出服务器传来的字节数组,并转换为某种类型的消息对象,因为Tcp等长连接协议涉及到粘包的问题,所以这里的处理针对完全没接触过的人来说比较难懂,可以根据具体的通信消息协议,参照框架内置的TcpChannel进行扩展,如果是Udp等非面向连接的,也可以照搬UdpChannel的内容。

注意:ReceiveMessage方法会由子线程启动,如果在其中会访问到UnityEngine的某些只限于主线程访问的模块,请使用如下方式将调用权返回主线程:

//如果这里是在子线程中

Main.Current.QueueOnMainThread(() =>
{
//这里的操作已返回主线程
});

启用通信管道

在属性面板点击Add Channel按钮,添加你想要启用的管道:

【Unity】 HTFramework框架(二十六)Network网络客户端_服务器_02


注意:如果本机测试,服务器IP和客户端IP可以一样,但端口尽量不要相同,且客户端IP理论上一直是127.0.0.1即可。

注意:不准备使用的管道请一定要从启用列表中移除!以避免不必要的资源开销。

开始网络通信

本文假定你有一个基本的Socket通信服务器,使用内置的通信管道进行一些基本的通信需求。

注意:理论上每个管道只能使用一种通信消息协议,比如内置的TcpChannel管道使用TcpNetworkInfo消息协议,UdpChannel管道使用UdpNetworkInfo消息协议(消息协议必须实现接口INetworkMessage)。

启动服务器

【服务器控制台】

【Unity】 HTFramework框架(二十六)Network网络客户端_网络_03

启动客户端主场景

包含框架主模块的客户端Scene,请确认Network模块的检视面板上必须已启用你接下来将要使用的管道。

连接服务器【面向连接型管道】

面向连接型管道必须连接服务器才能正常通讯,如下方式连接服务器:

//使用 TcpChannel 管道连接服务器
Main.m_Network.ConnectServer<TcpChannel>();

有如下连接成功或失败的事件可供监控:

Main.m_Network.BeginConnectServerEvent += (channel) =>
{
LogTcpInfo(channel.ToString() + " 开始连接服务器......");
};
Main.m_Network.ConnectServerSuccessEvent += (channel) =>
{
LogTcpInfo(channel.ToString() + " 连接服务器成功!");
};
Main.m_Network.ConnectServerFailEvent += (channel) =>
{
LogTcpInfo(channel.ToString() + " 连接服务器失败!");
};

我们直接调用ConnectServer连接服务器:

【客户端控制台】

【Unity】 HTFramework框架(二十六)Network网络客户端_框架_04


【服务器控制台】

【Unity】 HTFramework框架(二十六)Network网络客户端_网络_05

发送消息并接受服务器返回消息【面向连接型管道】

使用如下方式发送消息至服务器,不过需要注意的是,对应的管道必须使用其对应的协议,否则会解析失败:

注意:什么管道对应什么协议,由你的管道的封装消息方法和接收消息方法来定,比如封装和接收的都是A协议,那么发送的数据也必须是A协议。

//使用 TcpChannel 管道发送 TcpNetworkInfo 协议的消息
Main.m_Network.SendMessage<TcpChannel>(new TcpNetworkInfo(0, 1, 2, 3, 4, 5, new List<string>() { "Tcp测试数据1", "Tcp测试数据2" }));

【客户端控制台】

【Unity】 HTFramework框架(二十六)Network网络客户端_框架_06


【服务器控制台】

【Unity】 HTFramework框架(二十六)Network网络客户端_服务器_07

发送消息并接受服务器返回消息【非面向连接型管道】

依然使用如下方式发送消息:

//使用 UdpChannel 管道发送 UdpNetworkInfo 协议的消息
Main.m_Network.SendMessage<UdpChannel>(new UdpNetworkInfo("Udp测试消息"));

【客户端控制台】

【Unity】 HTFramework框架(二十六)Network网络客户端_Unity_08


【服务器控制台】

【Unity】 HTFramework框架(二十六)Network网络客户端_HTFramework_09

主动断开连接【面向连接型管道】

面向连接型管道在通信结束后必须断开连接,使用如下方式断开连接:

//断开 TcpChannel 的连接, 必须发送断开连接请求(比如这里的主次命令皆为-1时代表通信结束,断开连接)
Main.m_Network.DisconnectServer<TcpChannel>(new TcpNetworkInfo(0, 0, -1, -1, 0, 0, null));

请注意:发起断开连接请求后,客户端并不会立即断开连接,他会等到服务器返回同样的断开连接消息时,才会断开,所以服务器必须要按同样的方式处理。

【客户端控制台】

【Unity】 HTFramework框架(二十六)Network网络客户端_框架_10


【服务器控制台】

【Unity】 HTFramework框架(二十六)Network网络客户端_HTFramework_11


请注意:某一个管道断开连接后,完全不会影响其他管道的通信状态。

关闭服务器

【服务器控制台】

【Unity】 HTFramework框架(二十六)Network网络客户端_HTFramework_12

扩展:关于心跳包机制和断线重连机制

HT框架并不包含如上两种机制,但可以按以下方式扩展:

心跳包机制

双端约定某一格式的消息为心跳包(比如这里的主次命令-1为断连请求,那么可以约定主次命令0为心跳包),只要连接成功:

1.服务器 每隔一定时间发送心跳包检测,如果某个客户端未回复心跳包,或回复的间隔超过设定的阈值,则直接踢掉该客户端。

2.客户端 被踢掉的客户端根据心跳包断供检测到连接已断开,进入断线重连机制

断线重连机制

1.客户端 当客户端检测到与服务器断连时,调用ConnectServer重新连接,如果重连成功,之前由于网络断开而堆积于发送缓存池的消息会被依次发出,如果重连失败,提供一个UI界面,让用户选择再次重连或退出程序。

运行时检视面板

在编辑器中运行时将会出现运行时检视面板(Runtime Data),主要用以调试或数据监测,目前面板如下:

【Unity】 HTFramework框架(二十六)Network网络客户端_HTFramework_13


1.Enabled Channels:显示当前运行中的管道和其通信协议类型,并标记其连接状态。