「前言」
现在的游戏基本上都是联网,所以联网真的很重要。所以这篇博客主要讲述关于Lua如何实现联网消息的收发。
我们直接使用LuaFramework框架自带的网络模块,去连接服务器,进行消息的收发,LuaFramework框架已经做好了消息协议号和粘拆包,这些都不用我们管,直接调用即可,所以我们只负责发和收就OK了。
消息的收发可以分为一下几个步骤:
● 绑定IP端口,进行连接
● 连接成功,发送信息
● 设置回调,进行接收
● 按钮点击,循环收发
LuaFramework的网络模块:
● NetworkManager「网络管理」
● SocketClient 「客户端」
● ByteBuffer「字节缓冲」
● Converter「转换器」
● Protocal 「消息协议」
绑定IP端口,进行连接
发起连接是联网的第一步,框架的发起连接有两个地方,第一个就是Mian脚本主函数入口,第二个就是Gmae脚本里
的Game.OnInitOK()方法里。Mian.lua脚本代码如下:
--主入口函数。从这里开始lua逻辑
require "Network"
function Main()
print("主入口函数。从这里开始lua逻辑")
local LuaHelper = LuaFramework.LuaHelper
local networkMgr = LuaHelper.GetNetManager()
local AppConst = LuaFramework.AppConst
--设置端口号
AppConst.SocketPort = 10004;
--设置id
AppConst.SocketAddress = "127.0.0.1";
--开始连接服务器
networkMgr:SendConnect();
end
连接成功,发送信息
服务器在收到信息后会自动LuaFramework会调用Network的OnSocket方法,在接收到连接成功的信息时,我们直接给服务器在发一条信息,用来测试。
代码如下:
--Socket消息--
function Network.OnSocket(key, data)
if key == 101 then
LuaFramework.Util.Log("连接服务器成功!");
Send()
end
end
function Send()
--拼接数据
LuaFramework.Util.Log('开始发送数据');
local buffer = LuaFramework.ByteBuffer.New();
buffer:WriteShort(Protocal.Message);
buffer:WriteString("追求梦想,壹叶成名!");
--进行发送
local LuaHelper = LuaFramework.LuaHelper
local networkMgr = LuaHelper.GetNetManager()
networkMgr:SendMessage(buffer);
LuaFramework.Util.Log('数据发送完毕');
end
● 设置回调,进行接收
LuaFramework框架在Network.lua脚本的Network.Start() 的方法里已经为我们设计好了消息回调,当收到不同的消息协号时,会调用不同的方法。
function Network.Start()
logWarn("Network.Start!!");
--表示当收到101协议(Protocal.Connect)时,回调Network.OnConnect方法
Event.AddListener(Protocal.Connect, this.OnConnect);
--表示当收到104协议(Protocal.Message)时,回调Network.OnMessage方法
Event.AddListener(Protocal.Message, this.OnMessage);
--表示当收到102协议(Protocal.Exception)时,回调Network.Exception方法
Event.AddListener(Protocal.Exception, this.OnException);
--表示当收到103协议(Protocal.Disconnect)时,回调Network.Disconnect方法
Event.AddListener(Protocal.Disconnect, this.OnDisconnect);
end
下面是Protocal 「消息协议」脚本:
Protocal = {
Connect = '101'; --连接服务器
Exception = '102'; --异常掉线
Disconnect = '103'; --正常断线
Message = '104'; --接收消息
}
注意事项:这个脚本LuaFramework框架已经为我们创建好,在Common-Protocal.lua下,我们不需要创建,只需要直接使用就行。
如果你想自己创建脚本进行关联,只需要引用 Event = require ‘events’ 进行设计回调就可以解决
参考如下:
require "Logic/Network"
Event = require 'events'
function Start()
--表示当收到101协议(Protocal.Connect)时,回调Network.OnConnect方法
Event.AddListener(Protocal.Connect, Network.OnConnect);
--表示当收到104协议(Protocal.Message)时,回调Network.OnMessage方法
Event.AddListener(Protocal.Message, Network.OnMessage);
end
在回调方法里,我们可以看到信息的接收是通过Network.OnMessage方法进行接收的,所以我们只需要在Network.OnMessage方法进行消息接收的处理即可。
如下:
function Network.OnMessage(buffer)
LuaFramework.Util.Log('调用OnMessage方法,接收到消息');
local str = buffer:ReadString();
LuaFramework.Util.Log('收到的字符串:'..str);
end
到这Lua客户端的连接,收消息,发消息就基本完成了。因为需要测试,所以就写了个C#简单的支持多连接,和循环接收的服务器,因为后面要测试点击按钮循环发送要用到。参考如下:
负责连接的脚本
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
namespace LuaServer
{
class Program
{
/// <summary>
/// 所有客户端管理列表
/// </summary>
public static List<ClientSocketController> AllClientList = new List<ClientSocketController>();
static void Main(string[] args)
{
Socket listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipAdr = IPAddress.Parse("127.0.0.1");
IPEndPoint ipEp = new IPEndPoint(ipAdr, 10004);
Console.WriteLine("正在绑定端口号");
listenfd.Bind(ipEp);
Console.WriteLine("端口号绑定完成,开启监听");
listenfd.Listen(100);
Console.WriteLine("服务器启动成功");
while (true)
{
try
{
Console.WriteLine("等待连接...");
Socket connfd = listenfd.Accept();
//创建客户端
ClientSocketController client = new ClientSocketController(connfd);
//把这个客户端添加进客户端管理列表
AllClientList.Add(client);
Console.WriteLine("当前有" + AllClientList.Count+"个用户连接");
}
catch (Exception e)
{
//打印错误原因
Console.WriteLine(e.ToString());
}
}
}
}
}
客户端控制器
using System;
using System.Net.Sockets;
using System.Threading;
/// <summary>
/// 客户端控制器
/// </summary>
namespace LuaServer
{
class ClientSocketController
{
/// <summary>
/// 用户链接的通道
/// </summary>
private Socket clientSocket;
/// <summary>
/// 接收线程
/// </summary>
Thread receiveThread;
public ClientSocketController(Socket socket)
{
clientSocket = socket;
//启动接收的方法
//开始收的线程
receiveThread = new Thread(ReceiveFromClient);
//启动收的线程
receiveThread.Start();
}
void ReceiveFromClient()
{
Console.WriteLine("收到了客户端发来的消息...");
try
{
//开始接收
while (true)
{
byte[] readBuffer = new byte[10004];
//开启接收
int ByteLenght = clientSocket.Receive(readBuffer);
if (ByteLenght > 0)
{
Console.WriteLine("服务器接收完毕!!");
string showByteString = "";
//把字节进行string拼接
for (int i = 0; i < ByteLenght; i++)
{
int b = (int)readBuffer[i];
showByteString += b.ToString() + " ";
}
Console.WriteLine("服务器接收字节流:" + showByteString);
//解析消息 消息长度+消息协议号+消息内容
Int16 messageLen = BitConverter.ToInt16(readBuffer, 0);
Int16 protocal = BitConverter.ToInt16(readBuffer, 2);
Int16 strLen = BitConverter.ToInt16(readBuffer, 4);
string msgContent = System.Text.Encoding.UTF8.GetString(readBuffer, 6, strLen);
Console.WriteLine("<服务器接收>长度:" + messageLen);
Console.WriteLine("<服务器接收>协议号:" + protocal);
Console.WriteLine("<服务器接收的消息内容>字符串:" + msgContent);
//收到之后把收到的信息,立即回复过去
byte[] writeBuffer = new byte[ByteLenght];
Array.Copy(readBuffer, writeBuffer, ByteLenght);
clientSocket.Send(writeBuffer);
Console.WriteLine("\n"+"服务器把这条消息回复给客户端。");
Console.WriteLine("服务器发送信息完毕!");
}
}
}
catch (Exception e)
{
Console.WriteLine("e.ToString" + e.ToString());
}
}
}
}
让我们开启服务器,运行起来测试一下:
我们可以看到客户端成功的连上了服务器,而服务器也成功的收到了客户端的消息,并且又把消息回发给了客户端,客户端收到消息后检索协议号为104,回调用了Network.OnMessage方法,并且进行消息的打印输出。
同时我们也可以看到,服务端收到的信息。字节流的前两位“34 0”表示消息长度为34字节,紧跟着的“104 0”代表协议号104。在字符串的封装中(buffer:WriteString),程序会先在buffer中添加字符串的长度,最后才是字符串的内容。“30 0”表示“追求梦想,壹叶成名!”。
总的来说,可以理解为 长度+协议号+字符串。
现在是不是就能正常的使用Lua进行联网收发消息了呢,加个按钮,可以尝试一下,当然也可以扩展下服务器。
按钮发送的话就不过多介绍了,详见lua按钮事件。
有好的想法可以自己尽情尝试哦。
努力积才能,壹叶便成名。