Концепция логических машин платформы Лямбда-Мю 3 позволяет с легкостью решать задачи работы с многими пользователями:
Разберем взаимодействие платформы с несколькими клиентами.
Чат-комната. Пользователи находятся в одной виртуальной комнате и обмениваются текстовыми сообщениями.
Файловая структура проекта представлена ниже.
Необходимые скрипты туториала находятся в репозитарии lm3.examples/chat.
Чтобы запустить платформу скачайте бинарный файл и необходимые библиотеки из репозитария lm3.engine.ce и скопируйте в корень проекта.
Сторону клиента реализует Android-приложение с
Разработка взаимодействия платформы Лямбда-Мю 3 с многими клиентами на конкретном примере.
Запрос:
{ Command = "DoAuthByName", Data = <string> }
Ответ (всем пользователям):
{ Command = "OnSendAll", Data = "Member connected: "..<string> }
Запрос:
{ Command = "DoSendAll", Data = <string> }
Ответ (всем пользователям):
{ Command = "OnSendAll", Data = "Member: "..<string> }
Объекты основной логической машины:
Диаграмма связей:
На логических машинах запросы обрабатываются следующим образом:
main / start.lua
lm3:Log("Starting server") lm3:LoadLibrary( {Alias = "sys", FileName = "lm3system"} ) lm3:Include("main_lib.lua") lm3:CreateLObject( { LibAlias = "sys", Type = "TCPServer", Name = "server" } ) server:SetAttr("SocCount", lmconf.MaxClientCount) lm3:CreateLObject( { LibAlias = "sys", Type = "DataPack", Name = "packer" } ) packer:SetAttr("BufCount", lmconf.MaxClientCount) lm3:CreateObject( { Type = "LMList", Name = "clients" } ) init_Auth("Auth") lm3:AddHandler("OnStart", function(o, ev) -- проверка конфигурации ЛМ if clients:DoPrepare(lmconf.BasePath.."client_lm/config.lua") == false then lm3:Log("client_lm prepare failed") end end) Auth:AddHandler("OnReply", function(o, ev) lm3:Log("Auth: OnReply: tag: "..tostring(ev.Tag).." : "..lm3:DataToString(ev.Data)) end) -- связи объектов server:Connect("OnConnect", "Auth", "DoConnect") server:Connect("OnDisconnect", "Auth", "DoDisconnect") server:Connect("OnIncoming", "packer", "DoUnpack") packer:Connect("OnPack", "server", "DoSend") packer:Connect("OnUnpack", "Auth", "DoIncoming") Auth:Connect("OnReply", "packer", "DoPackTagged") Auth:Connect("OnStartClientLM", "clients", "DoStart") Auth:Connect("OnStopClientLM", "clients", "DoStop") Auth:Connect("OnClientEvent", "clients", "DoEvent") clients:Connect("OnEvent", "Auth", "DoClientEvent")
main / main_lib.lua
-- объект Auth -- function init_Auth(_name) local obj = lm3:CreateObject( { Type = "Base", Name = _name } ) obj.ClientList = {} for i = 1, lmconf.MaxClientCount do obj.ClientList[i] = { isConnected = false, LMName = "", } end function obj.TagFromLMName(_name) return tonumber(_name:sub(5)) end -- подключение нового клиента -- старт ЛМ obj:AddInEvent("DoConnect", "int", function(o, ev) lm3:Log("New client connected: "..tostring(ev)) obj.ClientList[ev].isConnected = true obj.ClientList[ev].LMName = "clm_"..tostring(ev) lm3:Log("Start client LM:") if obj:OnStartClientLM( { Name = obj.ClientList[ev].LMName } ) == true then lm3:Log("Start client LM complete.") else lm3:Log("ERROR: Start client LM failed.") obj.ClientList[ev].isConnected = false end end) -- отключение клиента -- остановка ЛМ obj:AddInEvent("DoDisconnect", "int", function(o,ev) lm3:Log("Client disconnected: "..tostring(ev)) obj:OnStopClientLM(obj.ClientList[ev].LMName) obj.ClientList[ev].isConnected = false end) -- распределение данных от клиента obj:AddInEvent("DoIncoming", "table[Tag:int,Data:table[Command:string,Data:string]]", function(o, ev) if obj.ClientList[ev.Tag].isConnected ~= true then lm3:Log("ERROR: Incoming data from not connected client: "..tostring(ev.Tag)) else lm3:Log("Incoming data from client with tag: "..tostring(ev.Tag).." : "..lm3:DataToString(ev.Data)) obj:OnClientEvent({ LMName = obj.ClientList[ev.Tag].LMName, EventName = "OnExtEvent", Data = ev.Data }) end end) -- обработка данных от ЛМ obj:AddInEvent("DoClientEvent", "table[LMName:string,EventName:string,Data:table[Command:string,Data:string]]", function(o, ev) if ev.Data.Command == "OnSendAll" then for i = 1, lmconf.MaxClientCount do if obj.ClientList[i].isConnected then obj:OnReply( { Tag = i, Data = ev.Data } ) end end else local iClient = obj.TagFromLMName(ev.LMName) obj:OnReply( { Tag = iClient, Data = ev.Data } ) end end) -- отправить данные клиенту obj:AddOutEvent("OnReply", "table[Tag:int,Data:table[Command:string,Data:string]]") -- отправить данные в ЛМ obj:AddOutProc("OnClientEvent", "table[LMName:string,EventName:string,Data:any]", "bool") obj:AddOutProc("OnStartClientLM", "table[Name:string]", "bool") obj:AddOutProc("OnStopClientLM", "string", "bool") return obj end
main / client_lm / start.lua
lm3:LoadLibrary( {Alias = "sys", FileName = "lm3system"} ) -- объект Timer для alive сообщение lm3:CreateObject( { Type = "Timer", Name = "timer" } ) timer:SetAttr("Interval", 30*1000) lm3:AddHandler("OnStart", function(o, ev) timer:DoEnable(true) end) userName = nil -- обработчик ивента с основной логической машины lm3:AddHandler("OnExtEvent", function(o, ev) if ev.Command == "DoAuthByName" then userName = ev.Data lm3:DoExtEvent( { Command = "OnSendAll", Data = "Member connected: "..userName } ) elseif ev.Command == "DoSendAll" then if userName == nil then lm3:Log("Error: userName == nil") else lm3:DoExtEvent( { Command = "OnSendAll", Data = "Member "..userName..": "..ev.Data } ) end end end) timer:AddHandler("OnTick", function(o, ev) --lm3:Log("OnTick: send Alive") lm3:DoExtEvent( { Command = "Alive", Data = "" } ) end)
[client 1]
-- получение уникального имени 2020-11-27 19:02:14.044 1940-1940/com.example.lm3_client D/lm3: application: onCreate: uniqueName: 3360d 2020-11-27 19:02:14.060 1940-1984/com.example.lm3_client D/lm3: application: setNetworkStatus: 2 -- подключение к серверу 2020-11-27 19:02:14.060 1940-1984/com.example.lm3_client D/lm3: connect: startServerConnection 2020-11-27 19:02:14.061 1940-1985/com.example.lm3_client D/lm3: connect: start 2020-11-27 19:02:14.084 1940-1940/com.example.lm3_client D/lm3: activity: main: OnCreate 2020-11-27 19:02:14.188 1940-1985/com.example.lm3_client D/lm3: connect: setServerConnection: true 2020-11-27 19:02:14.189 1940-1985/com.example.lm3_client D/lm3: connect: done 2020-11-27 19:02:14.189 1940-1985/com.example.lm3_client D/lm3: connect: end 2020-11-27 19:02:14.189 1940-2027/com.example.lm3_client D/lm3: connect: start listen 2020-11-27 19:02:14.234 1940-1940/com.example.lm3_client D/lm3: activity: main: onResume -- авторизация 2020-11-27 19:02:15.189 1940-2027/com.example.lm3_client D/lm3: listen: DoAuthByName: 3360d 2020-11-27 19:02:15.190 1940-2027/com.example.lm3_client D/lm3: listen: serverSend 2020-11-27 19:02:15.252 1940-2027/com.example.lm3_client D/lm3: listen: OnSendAll: Member connected: 3360d 2020-11-27 19:02:24.392 1940-1940/com.example.lm3_client D/lm3: activity: main: -- отправка сообщения button OnClick: message: Hello 2020-11-27 19:02:24.392 1940-1940/com.example.lm3_client D/lm3: listen: DoSendAll: Hello 2020-11-27 19:02:24.392 1940-1940/com.example.lm3_client D/lm3: listen: serverSend 2020-11-27 19:02:24.424 1940-2027/com.example.lm3_client D/lm3: listen: OnSendAll: Member 3360d: Hello 2020-11-27 19:02:34.153 1940-2027/com.example.lm3_client D/lm3: listen: OnSendAll: Member 65c8c: Hi
[client 2]
-- получение уникального имени 2020-11-27 19:01:55.396 14523-14523/com.example.lm3_client D/lm3: application: onCreate: uniqueName: 65c8c 2020-11-27 19:01:55.527 14523-14556/com.example.lm3_client D/lm3: application: setNetworkStatus: 2 -- подключение к серверу 2020-11-27 19:01:55.527 14523-14556/com.example.lm3_client D/lm3: connect: startServerConnection 2020-11-27 19:01:55.529 14523-14557/com.example.lm3_client D/lm3: connect: start 2020-11-27 19:01:55.544 14523-14557/com.example.lm3_client D/lm3: connect: setServerConnection: true 2020-11-27 19:01:55.545 14523-14557/com.example.lm3_client D/lm3: connect: done 2020-11-27 19:01:55.545 14523-14557/com.example.lm3_client D/lm3: connect: end 2020-11-27 19:01:55.545 14523-14559/com.example.lm3_client D/lm3: connect: start listen 2020-11-27 19:01:55.573 14523-14523/com.example.lm3_client D/lm3: activity: main: OnCreate 2020-11-27 19:01:55.716 14523-14523/com.example.lm3_client D/lm3: activity: main: onResume -- авторизация 2020-11-27 19:01:56.546 14523-14559/com.example.lm3_client D/lm3: listen: DoAuthByName: 65c8c 2020-11-27 19:01:56.546 14523-14559/com.example.lm3_client D/lm3: listen: serverSend 2020-11-27 19:01:56.580 14523-14559/com.example.lm3_client D/lm3: listen: OnSendAll: Member connected: 65c8c 2020-11-27 19:02:14.398 14523-14559/com.example.lm3_client D/lm3: listen: OnSendAll: Member connected: 3360d 2020-11-27 19:02:23.602 14523-14559/com.example.lm3_client D/lm3: listen: OnSendAll: Member 3360d: Hello -- отправка сообщения 2020-11-27 19:02:33.103 14523-14523/com.example.lm3_client D/lm3: activity: main: button OnClick: message: Hi 2020-11-27 19:02:33.103 14523-14523/com.example.lm3_client D/lm3: listen: DoSendAll: Hi 2020-11-27 19:02:33.103 14523-14523/com.example.lm3_client D/lm3: listen: serverSend 2020-11-27 19:02:33.139 14523-14559/com.example.lm3_client D/lm3: listen: OnSendAll: Member 65c8c: Hi
[server] LM_main.log
[2020-11-27 19:01:30][INFO:LMInit][Start logic machine v3.3(Build:555) ----------------------------------] [2020-11-27 19:01:30][LUA:LMCore][Starting server] [2020-11-27 19:01:30][TRACE:LMInit][Create library object: server] [2020-11-27 19:01:30][TRACE:LMInit][Create library object: packer] [2020-11-27 19:01:30][TRACE:LMInit][Create object: clients] [2020-11-27 19:01:30][TRACE:LMInit][Create object: Auth] [2020-11-27 19:01:30][INFO:LMInit][Initialization complete.] [2020-11-27 19:01:48][LUA:LMCore][New client connected: 1] [2020-11-27 19:01:48][LUA:LMCore][Start client LM:] [2020-11-27 19:01:48][LUA:LMCore][Start client LM complete.] -- авторизация первого клиента [2020-11-27 19:01:49][LUA:LMCore][Incoming data from client with tag: 1 : [Table:2] "Command" = [String] "DoAuthByName" "Data" = [String] "65c8c"] [2020-11-27 19:01:49][LUA:LMCore][Auth: OnReply: tag: 1 : [Table:2] "Command" = [String] "OnSendAll" "Data" = [String] "Member connected: 65c8c"] [2020-11-27 19:02:06][LUA:LMCore][New client connected: 2] [2020-11-27 19:02:06][LUA:LMCore][Start client LM:] [2020-11-27 19:02:06][LUA:LMCore][Start client LM complete.] -- авторизация второго клиента [2020-11-27 19:02:07][LUA:LMCore][Incoming data from client with tag: 2 : [Table:2] "Command" = [String] "DoAuthByName" "Data" = [String] "3360d"] [2020-11-27 19:02:07][LUA:LMCore][Auth: OnReply: tag: 1 : [Table:2] "Command" = [String] "OnSendAll" "Data" = [String] "Member connected: 3360d"] [2020-11-27 19:02:07][LUA:LMCore][Auth: OnReply: tag: 2 : [Table:2] "Command" = [String] "OnSendAll" "Data" = [String] "Member connected: 3360d"] -- сообщение от первого клиента [2020-11-27 19:02:16][LUA:LMCore][Incoming data from client with tag: 2 : [Table:2] "Command" = [String] "DoSendAll" "Data" = [String] "Hello"] [2020-11-27 19:02:16][LUA:LMCore][Auth: OnReply: tag: 1 : [Table:2] "Command" = [String] "OnSendAll" "Data" = [String] "Member 3360d: Hello"] [2020-11-27 19:02:16][LUA:LMCore][Auth: OnReply: tag: 2 : [Table:2] "Command" = [String] "OnSendAll" "Data" = [String] "Member 3360d: Hello"] [2020-11-27 19:02:18][LUA:LMCore][Auth: OnReply: tag: 1 : [Table:2] "Command" = [String] "Alive" "Data" = [String] ""] -- сообщение от второго клиента [2020-11-27 19:02:26][LUA:LMCore][Incoming data from client with tag: 1 : [Table:2] "Command" = [String] "DoSendAll" "Data" = [String] "Hi"] [2020-11-27 19:02:26][LUA:LMCore][Auth: OnReply: tag: 1 : [Table:2] "Command" = [String] "OnSendAll" "Data" = [String] "Member 65c8c: Hi"] [2020-11-27 19:02:26][LUA:LMCore][Auth: OnReply: tag: 2 : [Table:2] "Command" = [String] "OnSendAll" "Data" = [String] "Member 65c8c: Hi"] [2020-11-27 19:02:36][LUA:LMCore][Auth: OnReply: tag: 2 : [Table:2] "Command" = [String] "Alive" "Data" = [String] ""] [2020-11-27 19:02:48][LUA:LMCore][Auth: OnReply: tag: 1 : [Table:2] "Command" = [String] "Alive" "Data" = [String] ""] [2020-11-27 19:03:06][INFO:LMCore][Stop logic machine.]