开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:1871

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 3113|回复: 16

[碧俐千仞] Unity3D热更新LuaFramework入门实战(6)——网络

[复制链接]  [移动端链接]
排名
17035
昨日变化
8

23

主题

176

帖子

686

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
26
蛮牛币
1892
威望
0
注册时间
2014-11-6
在线时间
107 小时
最后登录
2017-8-13

专栏作家

发表于 2016-9-17 00:25:28 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x

如今大部分的游戏都是网络游戏,网络游戏便涉及到网络连接发起、网络数据接收等内容。LuaFramework内置了网络模块(NetworkManager、SocketClient、ByteBuffer、Converter、Protocal),本篇将会介绍该模块的调用方法以及其原理。由于不是基础章节,文章不会详细讲解基础知识,如果读者想要了解网络相关的内容,可以参考笔者即将出版的书籍《Unity3D网络游戏实战》中第六章“网络基础”。
知乎 @罗培羽


1、发起连接

发起连接是客户端网络通信的第一步,LuaFramewor中,只需通过LuaFramework.AppConst.SocketAddress和LuaFramework.AppConst.SocketPort设置ip和端口,然后调用NetworkManager的SendConnect方法即可发起连接。Main.lua的代码如下:
require "Network"

--主入口函数。从这里开始lua逻辑
function Main()
        local LuaHelper = LuaFramework.LuaHelper
       local networkMgr = LuaHelper.GetNetManager()
       local AppConst = LuaFramework.AppConst
       AppConst.SocketPort = 1234;
       AppConst.SocketAddress = "127.0.0.1";
       networkMgr:SendConnect();
end

在收到服务端回应后,LuaFramework会调用Network的OnSocket方法(写死)。新建名为Network.lua的文件,处理消息回调。在如下的代码中,Protocal代表协议号,比如“连接服务器”(Protocal.Connect)的协议号是101,在OnSocket的参数中,key便是收到的协议号,data是收到的数据。
Network = {};

--协议
Protocal = {
       Connect        = '101';        --连接服务器
       Exception   = '102';        --异常掉线
       Disconnect  = '103';        --正常断线   
       Message        = '104';        --接收消息
}

--Socket消息--
function Network.OnSocket(key, data)
       if key == 101 then
              LuaFramework.Util.Log('OnSocket Connect');
       else
              LuaFramework.Util.Log('OnSocket Other');
       end
end

为了测试网络功能,需要编写服务端,这里使用c#编写一套简单的服务端程序,仅为调试使用,代码如下:
using System;
using System.Net;
using System.Net.Sockets;
using System.Linq;

class MainClass
{
       public static void Main(string[] args)
       {
              Console.WriteLine("Hello World!");
              //Socket
              Socket listenfd = new Socket(AddressFamily.InterNetwork,
                                                  SocketType.Stream, ProtocolType.Tcp);
              //Bind
              IPAddress ipAdr = IPAddress.Parse("127.0.0.1");
              IPEndPoint ipEp = new IPEndPoint(ipAdr, 1234);
              listenfd.Bind(ipEp);
              //Listen
              listenfd.Listen(0);
              Console.WriteLine("[服务器]启动成功");
              while (true)
              {
                     //Accept
                     Socket connfd = listenfd.Accept();
                     Console.WriteLine("[服务器]Accept");
              }
       }
}

运行服务端和客户端,客户端会发起连接,服务端accept该连接后回应,客户端会显示“OnSocket Connect”
Unity3D热更新LuaFramework入门实战61985.png
图:服务端

Unity3D热更新LuaFramework入门实战61994.png
图:客户端

此时把服务端关掉(断开连接),客户端会收到协议号为102的消息,即异常掉线(Exception)。

Unity3D热更新LuaFramework入门实战62053.png

图:异常掉线

调用NetworkManager.SendConnect实际是调用BeginConnect发起连接。连接之后,回调OnConnect方法。
Unity3D热更新LuaFramework入门实战62133.png
图:连接过程

OnConnect方法调用NetworkManager.AddEvent,排除设计模式的内容,相当于调用Network.lua的OnSocket方法。传入OnSocket的第1个参数为101(Protocal.Connect),指代协议名,第2个参数是空的字节流。网络模块中定义了101、102、103这3个固定的协议号,分别代表连接服务器、异常断线和正常断线。
Unity3D热更新LuaFramework入门实战62324.png
图:连接回调

2、发送和接收

接下来尝试发送和接收数据。LuaFramework默认(如果不去改它的代码)使用的协议格式如下图所示,前面的2个字节为消息长度,用于处理沾包分包,随后的2个字节代表协议号(如上面的101、102、103),最后才是消息的内容。
Unity3D热更新LuaFramework入门实战62453.png
图:协议
修改Network.lua,在连接成功后(OnSocket方法的101协议),调用send发送一串协议号为104的数据。服务端收到数据后回射给客户端,客户端在收到回应后(OnSocket方法的104协议),读取并显示出来。
send方法中新建了一个buffer,然后往buffer中添加协议号(104)和协议内容(字符串:《Unity3D网络游戏实战》是一本好书!),最后调用networkMgr:SendMessage()发送数据。networkMgr:SendMessage()会自动计算协议长度,并附加到buffer上发送出去。
--Socket消息--
function Network.OnSocket(key, data)
       if key == 101 then
              LuaFramework.Util.Log('OnSocket Connect');
              Send()
       elseif key == 104 then
              LuaFramework.Util.Log('OnSocket Message ');
              local str = data:ReadString();
              LuaFramework.Util.Log('收到的字符串:'..str);
       else
              LuaFramework.Util.Log('OnSocket Other '..key);
       end
end

function Send()
       --组装数据
       local buffer = LuaFramework.ByteBuffer.New();
       buffer:WriteShort(Protocal.Message);
       buffer:WriteString("《Unity3D网络游戏实战》是一本好书!");
       --发送
       local LuaHelper = LuaFramework.LuaHelper
       local networkMgr = LuaHelper.GetNetManager()
       networkMgr:SendMessage(buffer);
       LuaFramework.Util.Log('数据发送完毕');
end

修改服务端程序,读出接收到的内容,并echo回去。
public static void Main(string[] args)
{
       略,没有改动
       while (true)
       {
       //Accept
              Socket connfd = listenfd.Accept();
              Console.WriteLine("[服务器]Accept");
              //Recv 不考虑各种意外,只做测试
              byte[] readBuff = new byte[100];
              int count = connfd.Receive(readBuff);
              //显示字节流
              string showStr = "";
              for (int i = 0; i < count; i++)
              {
                     int b = (int)readBuff;
                     showStr += b.ToString() + " ";
              }
              Console.WriteLine("[服务器接收]字节流:"+ showStr);
              //解析协议
              Int16 messageLen = BitConverter.ToInt16(readBuff,0);
              Int16 protocal = BitConverter.ToInt16(readBuff,2);
              Int16 strLen = BitConverter.ToInt16(readBuff,4);
              string str = System.Text.Encoding.UTF8.GetString(readBuff, 6, strLen);
              Console.WriteLine("[服务器接收] 长度:" + messageLen);
              Console.WriteLine("[服务器接收] 协议号:" + protocal);
              Console.WriteLine("[服务器接收] 字符串:" + str);
              //Send(echo)
              byte[] writeBuff = new byte[count];
              Array.Copy(readBuff,writeBuff,count);
              connfd.Send(writeBuff);
       }
}

运行游戏,可以看到服务端收到的如图所示的信息。字节流的前两位“53 0”表示消息长度为53字节,紧跟着的“104 0”代表协议号104。在字符串的封装中(buffer:WriteString),程序会先在buffer中添加字符串的长度,最后才是字符串的内容。“49 0”即表示“《Unity3D网络游戏实战》是一本好书!”占用49个字节(14个中文符号,每个3字节,7个英文符号,每个1字节)。协议长度53字节 = 协议号2个字节 + 字符串长度2字节 + 字符串内容49字节。
Unity3D热更新LuaFramework入门实战64634.png
图:服务端收到的信息
客户端收到服务端回射的消息后,也会显示出来,如下图所示。

Unity3D热更新LuaFramework入门实战64676.png
图:客户端收到的消息

在lua中调用networkMgr:SendMessage(buffer)时,实际上相当于调用了SocketClient的WriteMessage方法,该方法会计算协议的长度,然后将长度和内容组装在一起,调用BeginWrite发送数据。
Unity3D热更新LuaFramework入门实战64810.png
图:发送数据

在建立连接后,SocketClient会调用BeginRead,当收到服务端的消息时,回调OnRead方法。OnRead又调用了OnReceive方法。
Unity3D热更新LuaFramework入门实战64897.png
图:接收数据过程

OnReceive方法完成沾包分包处理,然后调用AddEvent方法分发消息(相当于调用了lua中NetWork表的OnSocket方法)。
Unity3D热更新LuaFramework入门实战64980.png
图:解析数据过程

关于BeginRead、BeginConnect等方法的介绍,读者可以查看c#网络编程的资料或参照《Unity3D网络游戏实战》第6章“网络基础”。

3、消息分发

一款游戏往往涉及很多条网络通信协议,在Network.OnSocket中,如果只用ifelse语句处理不同协议,代码往往会混乱不堪。LuaFramework集成了消息分发的方法,用法如下所示。
1、引用LuaFramework\Lua\events.lua,然后使用Event.AddListener添加监听,例如“Event.AddListener(Protocal.Connect, Network.OnConnect); ”表示当收到101协议(Protocal.Connect)时,回调Network.OnConnect方法。Main.lua代码如下:
require "Network"
Event = require 'events'

--主入口函数。从这里开始lua逻辑
function Main()
       local LuaHelper = LuaFramework.LuaHelper
       local networkMgr = LuaHelper.GetNetManager()
       local AppConst = LuaFramework.AppConst
       AppConst.SocketPort = 1234;
       AppConst.SocketAddress = "127.0.0.1";
       Event.AddListener(Protocal.Connect, Network.OnConnect);
       Event.AddListener(Protocal.Message, Network.OnMessage);
       networkMgr:SendConnect();
end


2、在需要分发消息的地方调用Event.Brocast,然后编写相应的回调函数。Network.lua的部分代码如下:
--Socket消息--
function Network.OnSocket(key, data)
       LuaFramework.Util.Log('OnSocket 消息分发:'..key);
       Event.Brocast(tostring(key), data);
end

function Network.OnConnect(data)
       LuaFramework.Util.Log('Network.OnConnect');
       Send()
end

function Network.OnMessage(data)
       LuaFramework.Util.Log('Network.OnMessage');
       local str = data:ReadString();
       LuaFramework.Util.Log('收到的字符串:'..str);
end

运行游戏,可以看到消息分发的结果。
Unity3D热更新LuaFramework入门实战66268.png
图:消息分发

调用Event.AddListener,实际上是在一个表中添加数据,把某个协议号对应于某个方法的信息记录起来。
Unity3D热更新LuaFramework入门实战66334.png
图:AddListener的过程

当调用Event.Brocast时,程序会查找这份表,然后执行回调方法。这里使用了协程来调用回调函数。使用协程的目的应该是不让回调逻辑阻碍主体逻辑,然而由于协程是单线程的,这点不起作用。除非回调函数也使用协程,相互配合。所以这里应该可以不用协程的。
Unity3D热更新LuaFramework入门实战66479.png
图:Brocast的过程

至此,读者应该理解LuaFramework网络模块的使用方法了。《Unity3D网络游戏实战》中,第六章“网络基础”,第七章“服务端框架”,第八章“客户端网络模块”都讲解网络有关的内容,并介绍一套网络框架的实现方法,相信对读者能有帮助。

最后依然是广告时间:
两款好玩的flash枪战小游戏(模式很创新的,不要说是很坑爹!!)
http://www.4399.com/flash/104592.htm
http://www.4399.com/flash/118114.htm

评分

参与人数 2鲜花 +7 收起 理由
hariboot + 5 很给力!
Vampire801 + 2 很给力!

查看全部评分


回复

使用道具 举报

排名
21478
昨日变化
16

0

主题

47

帖子

72

积分

Rank: 2Rank: 2

UID
169092
好友
0
蛮牛币
146
威望
0
注册时间
2016-9-18
在线时间
11 小时
最后登录
2017-9-20
发表于 2016-9-18 19:30:36 | 显示全部楼层
感谢分享!!

回复

使用道具 举报

7日久生情
2011/5000
排名
573
昨日变化
1

1

主题

530

帖子

2011

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
111260
好友
0
蛮牛币
7301
威望
0
注册时间
2015-6-30
在线时间
342 小时
最后登录
2017-9-23
发表于 2016-9-19 14:26:44 | 显示全部楼层

感谢分享!!

回复

使用道具 举报

排名
524
昨日变化
1

23

主题

288

帖子

2036

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
4057
好友
5
蛮牛币
3290
威望
0
注册时间
2013-9-17
在线时间
513 小时
最后登录
2017-8-17

社区QQ达人

发表于 2016-9-19 16:30:52 | 显示全部楼层
在lua里面添加点击事件的参数C#里面要怎么修改?我这样写报错了
[AppleScript] 纯文本查看 复制代码
prompt:AddClick(MainPanel.btnTask,{gameObject,1,"2"}, this.OnClick);


[C#] 纯文本查看 复制代码
        public void AddClick(GameObject go, object[] args, LuaFunction luafunc)
        {
            if (go == null || luafunc == null) return;
            buttons.Add(go.name, luafunc);
            go.GetComponent<Button>().onClick.AddListener(
                delegate() {
                    luafunc.Call(args);
                }
            );
        }

回复 支持 反对

使用道具 举报

0

主题

5

帖子

8

积分

Rank: 1

UID
62967
好友
0
蛮牛币
17
威望
0
注册时间
2015-4-29
在线时间
3 小时
最后登录
2016-9-25
发表于 2016-9-20 00:52:43 | 显示全部楼层
感谢分享

回复

使用道具 举报

6蛮牛粉丝
1170/1500
排名
1239
昨日变化
5

2

主题

74

帖子

1170

积分

Rank: 6Rank: 6Rank: 6

UID
133503
好友
2
蛮牛币
3143
威望
0
注册时间
2016-1-5
在线时间
316 小时
最后登录
2017-9-23
QQ
发表于 2016-9-20 08:39:06 | 显示全部楼层
请问楼主 你的《Unity3D网络游戏实战》什么时候能买到呢?

回复 支持 反对

使用道具 举报

排名
17035
昨日变化
8

23

主题

176

帖子

686

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
26
蛮牛币
1892
威望
0
注册时间
2014-11-6
在线时间
107 小时
最后登录
2017-8-13

专栏作家

 楼主| 发表于 2016-9-20 09:30:34 | 显示全部楼层
吴肖牧 发表于 2016-9-19 16:30
在lua里面添加点击事件的参数C#里面要怎么修改?我这样写报错了
[mw_shl_code=applescript,true]prompt:Add ...

":"表示把自己传入到第一个参数中,所以把:改成.吧

回复 支持 反对

使用道具 举报

排名
17035
昨日变化
8

23

主题

176

帖子

686

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
26
蛮牛币
1892
威望
0
注册时间
2014-11-6
在线时间
107 小时
最后登录
2017-8-13

专栏作家

 楼主| 发表于 2016-9-20 09:30:44 | 显示全部楼层
吴肖牧 发表于 2016-9-19 16:30
在lua里面添加点击事件的参数C#里面要怎么修改?我这样写报错了
[mw_shl_code=applescript,true]prompt:Add ...

":"表示把自己传入到第一个参数中,所以把:改成.吧

回复 支持 反对

使用道具 举报

排名
17035
昨日变化
8

23

主题

176

帖子

686

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
26
蛮牛币
1892
威望
0
注册时间
2014-11-6
在线时间
107 小时
最后登录
2017-8-13

专栏作家

 楼主| 发表于 2016-9-20 09:31:45 | 显示全部楼层
wp1947 发表于 2016-9-20 08:39
请问楼主 你的《Unity3D网络游戏实战》什么时候能买到呢?

现在已经排版好了,在校稿,应该很快了、大出版社的流程就是比较多啊~~

回复 支持 反对

使用道具 举报

排名
524
昨日变化
1

23

主题

288

帖子

2036

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
4057
好友
5
蛮牛币
3290
威望
0
注册时间
2013-9-17
在线时间
513 小时
最后登录
2017-8-17

社区QQ达人

发表于 2016-9-20 18:10:52 | 显示全部楼层
楼主 我现在在拓展这个框架  可以加个Q不

回复 支持 反对

使用道具 举报

排名
27751
昨日变化
18

0

主题

12

帖子

30

积分

Rank: 1

UID
65524
好友
0
蛮牛币
75
威望
0
注册时间
2015-1-4
在线时间
14 小时
最后登录
2017-4-15
QQ
发表于 2016-9-24 11:46:15 | 显示全部楼层
出版后 通知一下

回复

使用道具 举报

排名
17035
昨日变化
8

23

主题

176

帖子

686

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
26
蛮牛币
1892
威望
0
注册时间
2014-11-6
在线时间
107 小时
最后登录
2017-8-13

专栏作家

 楼主| 发表于 2016-9-27 10:23:07 | 显示全部楼层
吴肖牧 发表于 2016-9-20 18:10
楼主 我现在在拓展这个框架  可以加个Q不

可以啊,邮箱aglab#foxmail#com

回复 支持 反对

使用道具 举报

排名
17035
昨日变化
8

23

主题

176

帖子

686

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
26
蛮牛币
1892
威望
0
注册时间
2014-11-6
在线时间
107 小时
最后登录
2017-8-13

专栏作家

 楼主| 发表于 2016-9-27 10:23:21 | 显示全部楼层
MC小R 发表于 2016-9-24 11:46
出版后 通知一下

恩恩,好啊

回复 支持 反对

使用道具 举报

排名
17035
昨日变化
8

23

主题

176

帖子

686

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
26
蛮牛币
1892
威望
0
注册时间
2014-11-6
在线时间
107 小时
最后登录
2017-8-13

专栏作家

 楼主| 发表于 2016-12-6 22:34:38 | 显示全部楼层
MC小R 发表于 2016-9-24 11:46
出版后 通知一下

《Unity3D网络游戏实战》已经出版了,感谢关注^_^

回复 支持 反对

使用道具 举报

6蛮牛粉丝
1449/1500
排名
1216
昨日变化

5

主题

201

帖子

1449

积分

Rank: 6Rank: 6Rank: 6

UID
10760
好友
1
蛮牛币
3035
威望
0
注册时间
2013-12-20
在线时间
413 小时
最后登录
2017-9-21
发表于 2017-3-22 10:54:15 | 显示全部楼层
前面章节学习过来的,很给力。问一下大神,对于lua热更这块需要系统性的学习lua编程吗?还是把大部分逻辑放在C#脚本中,lua只负责简单调用就行了?

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表