Net网络框架基于Socket网络库扩展而成的一款强大的多人在线网络游戏插件(框架),那么下面我就带领大家来学习一个这款网络插件(框架)的开发过程。
首先,你的安装unity, 只要unity支持.net4.x版本以上都可以使用此插件框架,那么安装那一步骤我就不一一介绍了。。
第一个步:我们创建一个游戏项目文件
点击确定后,进入unity软件。
然后获取我们的网络框架插件:
上图加群免认证,直接去群文件下载游戏框架插件。
然后进行解压,直接拖到项目中, 下图是插件文件结构
我们创建一个脚本,叫做网络管理器:
然后双击脚本进入VS2017代码编辑器,然后写上以下代码, 你可以直接复制粘贴
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Net.Client;//网络游戏的客户端命名空间
using Net.Share;//网络服务器的通用命名空间
using System;
//网络游戏管理器
public class NetworkManager : NetClient//继承网络游戏核心客户端基类
{
// Start is called before the first frame update
void Start()
{
Connect();//1.开始连接服务器
}
public void MyConnect()
{
Connect("127.0.0.1", 666, result => //2.连接服务器
{
//result 为 true 则连接成功, 为假则连接失败 , 此处代码处于多线程, 不允许调用unity的api
});
}
//当连接服务器成功调用
protected override void OnConnected()
{
//此函数处于unity线程, 可以使用unity的api
Debug.Log("连接成功");
}
//当连接失败调用
protected override void OnConnectFailed()
{
//在此函数处理连接失败后的动作
Debug.Log("连接失败");
}
//当客户端与服务器连接中断调用
protected override void OnConnectLost()
{
//处理
Debug.Log("连接中断");
}
//当断开连接调用
protected override void OnDisconnect()
{
//处理
Debug.Log("断开连接");
}
//当连接被断开并且尝试重新连接服务器时调用
protected override void OnTryToConnect()
{
//处理
Debug.Log("尝试重连");
}
//当断线重新连接服务器成功调用
protected override void OnReconnect()
{
//处理
Debug.Log("断线重连成功");
}
//当注册网络类型
protected override Type[] OnRegNetworkTypes()
{
Debug.Log("注册网络类型");
return new Type[] { typeof(int), typeof(bool), typeof(string), typeof(float) };//注册你的网络类型
}
}
那么客户端已经有了管理器进行连接服务器的类了, 那么我们现在就要进行编写服务器代码了。
首先我们创建一个C#控制台项目:选择解决方案, 然后右键-> 添加->新建项目
选择C#->控制台应用->项目名称, 最后确认就创建好了我们的服务器项目
我们在服务器的引用那里右键,然后选择浏览,找到unity的三个dll和GameDesigner.dll文件,然后确认就好了, unity的dll在unity的安装目录下找到, GameDesigner.dll文件就是我们的网络插件dll,在项目里面可以找到
新建一个服务器管理器脚本,这个脚本也是最主要的脚本:
然后写上代码: 可以直接复制过去粘贴
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Net.Server;//网络游戏服务器命名空间
using Net.Share;//网络游戏通用命名空间
namespace Server
{
//服务器管理器
public class ServerManager : NetServer//继承网络游戏的服务器核心基类
{
//当服务器开始启动调用
protected override void OnStarting()
{
//处理
Console.WriteLine("初始化服务器");
}
//当服务器启动成功,启动完成调用
protected override void OnStartupCompleted()
{
//处理
Console.WriteLine("服务器启动成功");
}
//当有客户端玩家连接调用
protected override void OnHasConnect(EndPoint client)//玩家客户端终端
{
//处理
Console.WriteLine("有客户端连接" + client.ToString());
}
//当服务器创建主场景调用, 返回主场景键值对, 键为场景名称 值为场景实例
protected override KeyValuePair OnAddDefaultScene()
{
Console.WriteLine("当添加网络主场景");
return new KeyValuePair("主场景", new NetScene(1000));//返回了一个主场景,并且初始化主场景容纳1000个人同时在主场景内
}
//当接收未知的客户端请求调用
protected override NetPlayer OnUnClientRequest(NetPlayer unClient, byte[] buffer, byte cmd, int index, int count)
{
//处理未知客户端数据请求 验证登录 或 注册
//如果让此函数返回对象实例, 则同意此客户端进入服务器的权限,并添加此客户端到在线玩家集合中, 之后就可以与在线玩家之间的交互,
//如果返回null, 则服务器不处理此客户端的任何事件, 可以认为服务器不允许此客户端进入游戏,或者登陆失败
Console.WriteLine("当未知客户端发来的数据请求, 默认直接授权进入多人在线");
return unClient; //默认服务器直接运行未知客户端进入多人在线集合
}
//当接收客户端的自定义byte[]数据请求, 此方法需要使用者自行编写序列化和反序列化进行解析网络数据, 可以使用josn解析 , 此插件使用NetConvert解析
protected override void OnReceiveBuffer(NetPlayer client, byte cmd, byte[] buffer, int index, int count)
{
Console.WriteLine("接收客户端玩家自定义数据请求:" + client.RemotePoint[GetType().GUID].ToString() + " 数据大小: " + count);
//处理自定义数据, 自定义数据客户端同样有一个自定义的Send方法进行发送数据封包
}
//当服务器初始化成功,并收集将要注册的RPC类型时调用, RPC函数是网络可以识别的函数,网络数据会调用那些带有RPC特性的函数, 关键在此方法进行添加
protected override List
然后在Main函数里写上服务器的实例,并启动服务器
我们可以看到服务器已经启动成功:
然后我们启动客户端进行连接, 能够看到客户端也已经能连接上服务器了
这时服务器有响应为有客户端连接, 可以看到客户端连接然后又退出游戏, 那是我连接上然后又关闭了客户端
那么现在我们就可以对服务器发送一下数据包了, 我们写个发送字符串函数, 代码如下, 可直接复制粘贴:
using UnityEngine;
using System.Collections;
using Net.Client;//网络游戏客户端命名空间
using Net.Share;//网络游戏通用命名空间
//发送消息类型
public class SendMessage : NetBehaviour //此时不能再继承NetClient类型了,//我们接下来所写的网络类型都要继承此NetBehaviour类型, NetBehaviour类型会收集网络RPC函数,如果不继承此类有可能无法调用类内部的RPC函数
{
private string str;//定义了我们要发送的字符串
private void OnGUI()
{
str = GUI.TextField(new Rect(100,100,200,50), str);//输入我们要发送的字符串
if (GUI.Button(new Rect(100, 200, 100, 50), "发送"))//如果按下按钮就进行发送数据到服务器
{
byte[] buffer = System.Text.Encoding.Unicode.GetBytes(str);//把我们要发送的字符串转出二进制数组的Unicode编码,然后进行发送
Send(buffer);//发送自定义网络数据
}
}
}
嗯, 我们有了发送数据类型了, 那么我们还需要在服务器那边处理一下接收自定义类型的数据: 下面代码可以覆盖ServerManager.cs的代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Net.Server;//网络游戏服务器命名空间
using Net.Share;//网络游戏通用命名空间
namespace Server
{
//服务器管理器
public class ServerManager : NetServer//继承网络游戏的服务器核心基类
{
//当服务器开始启动调用
protected override void OnStarting()
{
//处理
Console.WriteLine("初始化服务器");
}
//当服务器启动成功,启动完成调用
protected override void OnStartupCompleted()
{
//处理
Console.WriteLine("服务器启动成功");
}
//当有客户端玩家连接调用
protected override void OnHasConnect(EndPoint client)//玩家客户端终端
{
//处理
Console.WriteLine("有客户端连接" + client.ToString());
}
//当服务器创建主场景调用, 返回主场景键值对, 键为场景名称 值为场景实例
protected override KeyValuePair OnAddDefaultScene()
{
Console.WriteLine("当添加网络主场景");
return new KeyValuePair("主场景", new NetScene(1000));//返回了一个主场景,并且初始化主场景容纳1000个人同时在主场景内
}
//当接收未知的客户端请求调用
protected override NetPlayer OnUnClientRequest(NetPlayer unClient, byte[] buffer, byte cmd, int index, int count)
{
//处理未知客户端数据请求 验证登录 或 注册
//如果让此函数返回对象实例, 则同意此客户端进入服务器的权限,并添加此客户端到在线玩家集合中, 之后就可以与在线玩家之间的交互,
//如果返回null, 则服务器不处理此客户端的任何事件, 可以认为服务器不允许此客户端进入游戏,或者登陆失败
Console.WriteLine("当未知客户端发来的数据请求, 默认直接授权进入多人在线");
return unClient; //默认服务器直接运行未知客户端进入多人在线集合
}
//当接收客户端的自定义byte[]数据请求, 此方法需要使用者自行编写序列化和反序列化进行解析网络数据, 可以使用josn解析 , 此插件使用NetConvert解析
protected override void OnReceiveBuffer(NetPlayer client, byte cmd, byte[] buffer, int index, int count)
{
Console.WriteLine("接收客户端玩家自定义数据请求:" + client.RemotePoint[GetType().GUID].ToString() + " 数据大小: " + count);
string str = Encoding.Unicode.GetString(buffer, index, count);//接收自定义的数据请求, 数据请求编码要保证一致才能解码成功, 否则会解乱码
Console.WriteLine("接收的数据内容:" + str);
//处理自定义数据, 自定义数据客户端同样有一个自定义的Send方法进行发送数据封包
}
//当服务器初始化成功,并收集将要注册的RPC类型时调用, RPC函数是网络可以识别的函数,网络数据会调用那些带有RPC特性的函数, 关键在此方法进行添加
protected override List
我们添加了以下代码来解析客户端发来的Unicode编码数据:
然后在unity的场景层级里面找个物体进行添加了我们的SendMessage组件,运行一下服务器, 再运行客户端进行测试
当我们的客户端写入字符串然后按下发送按钮, 服务器就能看到打印出来一条信息了, 那么现在我们就来实现调用服务器的函数,以下代码为调用服务器函数代码, 可以复制黏贴
using UnityEngine;
using System.Collections;
using Net.Client;//网络游戏客户端命名空间
using Net.Share;//网络游戏通用命名空间
public class CallServerFunc : NetBehaviour//继承网络游戏行为基类
{
private string parStr;//定义了我们要发送的字符串参数
private void OnGUI()
{
parStr = GUI.TextField(new Rect(300, 100, 200, 50), parStr);//输入我们要发送的字符串参数
if (GUI.Button(new Rect(300, 200, 100, 50), "调用服务器的Test函数"))//如果按下按钮就进行发送数据到服务器
{
Send("Test", parStr);//发送插件内核处理好的RPC函数方法, 发送此数据,服务器必须有Test方法, 而且参数也要匹配
}
}
}
然后同样,我们要在服务器添加一个方法来接收客户端发送的函数调用请求
添加了Test方法后完整代码为以下代码, 直接复制黏贴到ServerManager.cs脚本覆盖就行
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Net.Server;//网络游戏服务器命名空间
using Net.Share;//网络游戏通用命名空间
namespace Server
{
//服务器管理器
public class ServerManager : NetServer//继承网络游戏的服务器核心基类
{
//当服务器开始启动调用
protected override void OnStarting()
{
//处理
Console.WriteLine("初始化服务器");
}
//当服务器启动成功,启动完成调用
protected override void OnStartupCompleted()
{
//处理
Console.WriteLine("服务器启动成功");
}
//当有客户端玩家连接调用
protected override void OnHasConnect(EndPoint client)//玩家客户端终端
{
//处理
Console.WriteLine("有客户端连接" + client.ToString());
}
//当服务器创建主场景调用, 返回主场景键值对, 键为场景名称 值为场景实例
protected override KeyValuePair OnAddDefaultScene()
{
Console.WriteLine("当添加网络主场景");
return new KeyValuePair("主场景", new NetScene(1000));//返回了一个主场景,并且初始化主场景容纳1000个人同时在主场景内
}
//当接收未知的客户端请求调用
protected override NetPlayer OnUnClientRequest(NetPlayer unClient, byte[] buffer, byte cmd, int index, int count)
{
//处理未知客户端数据请求 验证登录 或 注册
//如果让此函数返回对象实例, 则同意此客户端进入服务器的权限,并添加此客户端到在线玩家集合中, 之后就可以与在线玩家之间的交互,
//如果返回null, 则服务器不处理此客户端的任何事件, 可以认为服务器不允许此客户端进入游戏,或者登陆失败
Console.WriteLine("当未知客户端发来的数据请求, 默认直接授权进入多人在线");
return unClient; //默认服务器直接运行未知客户端进入多人在线集合
}
//当接收客户端的自定义byte[]数据请求, 此方法需要使用者自行编写序列化和反序列化进行解析网络数据, 可以使用josn解析 , 此插件使用NetConvert解析
protected override void OnReceiveBuffer(NetPlayer client, byte cmd, byte[] buffer, int index, int count)
{
Console.WriteLine("接收客户端玩家自定义数据请求:" + client.RemotePoint[GetType().GUID].ToString() + " 数据大小: " + count);
string str = Encoding.Unicode.GetString(buffer, index, count);//接收自定义的数据请求, 数据请求编码要保证一致才能解码成功, 否则会解乱码
Console.WriteLine("接收的数据内容:" + str);
//处理自定义数据, 自定义数据客户端同样有一个自定义的Send方法进行发送数据封包
}
//当服务器初始化成功,并收集将要注册的RPC类型时调用, RPC函数是网络可以识别的函数,网络数据会调用那些带有RPC特性的函数, 关键在此方法进行添加
protected override List
然后将CallServerFunc脚本挂载到游戏物体上,运行服务器,再运行客户端看看结果是什么样子的......
现在我们可以看到已经调用了服务器的Test函数了, 有点神奇吧!!!
那么我们现在还有一种方法哦, 就是调用客户端的函数, 这个调用客户端函数可不是本地调用哦, 是调用所有在同一场景内的客户端的指定方法。 那么现在我们就要在Send方法上用到cmd网络命令了, cmd有几十种网络命令, 也可以自行添加其他你想要的网络命令, 网络命令是byte类型的, 所以最多只能有256个网络命令, 插件内核采用了10个网络命令, 你还可以使用200多个命令,已经够用的了。。。
下面我们来看远程调用所有在同一场景内的客户端的Test函数:
using UnityEngine;
using System.Collections;
using Net.Client;//网络游戏客户端命名空间
using Net.Share;//网络游戏通用命名空间
//调用其他客户端与此客户端同一场景内的函数
public class CallClientFunc : NetBehaviour//继承网络游戏行为基类
{
private string parStr;//定义了我们要发送的字符串参数
private string netInfo;//存储聊天内容
private void OnGUI()
{
parStr = GUI.TextField(new Rect(300, 100, 200, 50), parStr);//输入我们要发送的字符串参数
if (GUI.Button(new Rect(300, 200, 100, 50), "调用服务器的Test函数"))//如果按下按钮就进行发送数据到服务器
{
//NetCmd.SceneCmd : 网络命令, SceneCmd:场景命令, 意义为调用所有在同一场景内的客户端玩家的xxx函数
//Test :远程调用识别的函数名称
//parStr : 远程调用的参数
Send(NetCmd.SceneCmd, "Test", parStr);//发送插件内核处理好的RPC函数方法, 发送此数据,服务器必须有Test方法, 而且参数也要匹配
}
GUI.TextField(new Rect(200, 500, 400, 200), netInfo);
}
//远程调用此函数
[RPCFun]
private void Test(string info)//远程参数
{
Debug.Log("xxx客户端调用了Test函数, 传参为:" + info);
netInfo += info;
}
}
上面代码写上后,我们不需要写服务器对接代码了, 因为那些已经声明过的网络命令已经被框架内核帮我们实现了,使用我们现在直接运行服务器, 然后再运行客户端进行测试,看看效果, 一个客户端是看不出什么效果的,所以我们要编译一个客户端来看看是不是两个unity都能显示同样的消息来:
经过刚才调用了一下,结果没有被调用, 经过几次的查找,终于找到了问题, 我们在初始化场景主场景时所给的主场景名为“主场景”, 而我们的客户端没有指定它所在的场景键为哪个场景, 我们需要把客户端的sceneID也改成主场景名称这样两个客户端才能相互得到转发权限
代码完整为以下代码, 直接复制黏贴到ServerManager.cs脚本就可以
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Net.Server;//网络游戏服务器命名空间
using Net.Share;//网络游戏通用命名空间
namespace Server
{
//服务器管理器
public class ServerManager : NetServer//继承网络游戏的服务器核心基类
{
//当服务器开始启动调用
protected override void OnStarting()
{
//处理
Console.WriteLine("初始化服务器");
}
//当服务器启动成功,启动完成调用
protected override void OnStartupCompleted()
{
//处理
Console.WriteLine("服务器启动成功");
}
//当有客户端玩家连接调用
protected override void OnHasConnect(EndPoint client)//玩家客户端终端
{
//处理
Console.WriteLine("有客户端连接" + client.ToString());
}
//当服务器创建主场景调用, 返回主场景键值对, 键为场景名称 值为场景实例
protected override KeyValuePair OnAddDefaultScene()
{
Console.WriteLine("当添加网络主场景");
return new KeyValuePair("主场景", new NetScene(1000));//返回了一个主场景,并且初始化主场景容纳1000个人同时在主场景内
}
//当接收未知的客户端请求调用
protected override NetPlayer OnUnClientRequest(NetPlayer unClient, byte[] buffer, byte cmd, int index, int count)
{
//处理未知客户端数据请求 验证登录 或 注册
//如果让此函数返回对象实例, 则同意此客户端进入服务器的权限,并添加此客户端到在线玩家集合中, 之后就可以与在线玩家之间的交互,
//如果返回null, 则服务器不处理此客户端的任何事件, 可以认为服务器不允许此客户端进入游戏,或者登陆失败
Console.WriteLine("当未知客户端发来的数据请求, 默认直接授权进入多人在线");
unClient.sceneID = "主场景";// 默认客户端开始登陆所在的场景为MainScene, 而上面给的主场景键为"主场景",所以客户端默认进入场景也要改sceneID为主场景的ID
return unClient; //默认服务器直接运行未知客户端进入多人在线集合
}
//当接收客户端的自定义byte[]数据请求, 此方法需要使用者自行编写序列化和反序列化进行解析网络数据, 可以使用josn解析 , 此插件使用NetConvert解析
protected override void OnReceiveBuffer(NetPlayer client, byte cmd, byte[] buffer, int index, int count)
{
Console.WriteLine("接收客户端玩家自定义数据请求:" + client.RemotePoint[GetType().GUID].ToString() + " 数据大小: " + count);
string str = Encoding.Unicode.GetString(buffer, index, count);//接收自定义的数据请求, 数据请求编码要保证一致才能解码成功, 否则会解乱码
Console.WriteLine("接收的数据内容:" + str);
//处理自定义数据, 自定义数据客户端同样有一个自定义的Send方法进行发送数据封包
}
//当服务器初始化成功,并收集将要注册的RPC类型时调用, RPC函数是网络可以识别的函数,网络数据会调用那些带有RPC特性的函数, 关键在此方法进行添加
protected override List
然后我们编译unity客户端,运行服务器, 再运行两个客户端进行测试
嗯, 已经可以看到调用本地两个客户端的Test函数了。。。有点惊喜吧
以上已经可以实现发送自定义数据, 发送RPC网络函数, 调用服务器函数 和 调用同一场景的所有客户端玩家了, 那么我们能不能调用所有服务器的客户端中的函数呢? 答案是可以的, 也就是换了个命令
将 Send(NetCmd.SceneCmd, "Test", parStr); 改成Send(NetCmd.AllCmd, "Test", parStr);就可以调用所有在线玩家的xx函数了
只需要改下命令就执行不同的功能了, 好激动的感觉有木有???
下面我列出几种网络命令和介绍: 代码已经注释的应该详细了, 你如果要自定义网络命令, 可以继承下面的网络命令类型,写上你自己想要的一些网络命令哦。。。
到此基础网络框架插件就结束了哦, 如果觉得不错此文章不错, 可以进行收藏转发哦, 如果对你很有帮助也可以给买包烟钱吧
下篇:服务器数据库处理也登陆注册