服务端Skynet(五)——如何搭建一个实例

news2024/11/15 3:58:01

服务端Skynet(五)——如何搭建一个实例

文章目录

  • 服务端Skynet(五)——如何搭建一个实例
    • 1、配置文件
    • 2、服务消息分发与回应(call/send)
    • 3、通信(server/client)
    • 4、Mysql连接

1、配置文件

​ 搭建一个实例 主要看 config 文件的设置,如下:

--config  

include "config.path"			-- 库文件、服务文件位置

-- preload = "./examples/preload.lua"	-- run preload.lua before every lua service run
thread = 8						-- 启动多少个线程
logger = nil					-- 输出日志保存到logger项指定的文件中
logpath = "."
harbor = 1						-- skynet初期版本提供了“master/slave”集群模式,后来又提供了更适用的“cluster”集群模式。
address = "127.0.0.1:2526"
master = "127.0.0.1:2013"
start = "main"	-- main script	  -- 主服务入口,路径为config文件同目录下
bootstrap = "snlua bootstrap"	-- The service for bootstrap
standalone = "0.0.0.0:2013"
-- snax_interface_g = "snax_g"
cpath = root.."cservice/?.so"	   -- -- 用c编写的服务模块的位置
-- daemon = "./skynet.pid"

--config.path
root = "./"
luaservice = root.."service/?.lua;"..root.."test/?.lua;"..root.."examples/?.lua;"..root.."test/?/init.lua"
lualoader = root .. "lualib/loader.lua"
lua_path = root.."lualib/?.lua;"..root.."lualib/?/init.lua"
lua_cpath = root .. "luaclib/?.so"
snax = root.."examples/?.lua;"..root.."test/?.lua"

我们可以把两个文件合并为一个config,再根据实例项目的目录设置相应的路径,例如我的实例路径:

在这里插入图片描述

-- 我的实例  config    其中skynet为同层所以相关路径要加一层  代码主要放在test 和 test/service 所以luaservice要加一下
root = "/home/XXX/skynet_test/"		--测试目录
thread = 8
logger = nil
logpath = "."
harbor = 1
address = "127.0.0.1:2526"
master = "127.0.0.1:2013"
start = "main"	-- main script
bootstrap = "snlua bootstrap"	-- 启动的第一个服务以及其启动参数 service/bootstrap.lua
standalone = "0.0.0.0:2013"
luaservice = root.."test/?.lua;"..root.."test/service/?.lua;"..root.."skynet/service/?.lua;"
lualoader = root .. "skynet/lualib/loader.lua"
lua_path = root.."skynet/lualib/?.lua;"..root.."skynet/lualib/?/init.lua"
lua_cpath = root .. "skynet/luaclib/?.so"
-- preload = "./example1/preload.lua"	-- run preload.lua before every lua service run
-- snax = root.."example1/?.lua;"..root.."test/?.lua"
-- snax_interface_g = "snax_g"
cpath = root.."skynet/cservice/?.so"
-- daemon = "./skynet.pid"


2、服务消息分发与回应(call/send)

skynet.send(address, typename, …) 把一条类别为 typename 的消息发送给 address 。它会先经过事先注册的 pack 函数打包 … 的内容。skynet.send 是一条非阻塞 API ,发送完消息后,coroutine 会继续向下运行,这期间服务不会重入。

skynet.call(address, typename, …) 会在内部生成一个唯一 session ,并向 address 提起请求,并阻塞等待对 session 的回应(可以不由 address 回应)。当消息回应后,还会通过之前注册的 unpack 函数解包。尤其需要留意的是,skynet.call 仅仅阻塞住当前的 coroutine ,而没有阻塞整个服务。在等待回应期间,服务照样可以响应其他请求。所以,尤其要注意,在 skynet.call 之前获得的服务内的状态,到返回后,很有可能改变

skynet.ret(message, size) 回应一个消息,它会将 message size 对应的消息附上当前消息的 session ,以及 skynet.PTYPE_RESPONSE 这个类别,发送给当前消息的来源 source

​ 由于 skynet 中最常用的消息类别是 lua ,这种消息是经过 skynet.pack 打包的,所以惯用法是 skynet.ret(skynet.pack(…)) 。skynet.pack(…) 返回一个 lightuserdata 和一个长度,符合 skynet.ret 的参数需求;与之对应的是 skynet.unpack(message, size) 它可以把一个 C 指针加长度的消息解码成一组 Lua 对象。

-- service.lua
local skynet = require "skynet"

require"skynet.manager" -- 引入 skynet.register

local db = {}

local command = {}


function command.get(key)
    print("command get :", key)
    return db[key]
end

function command.set(key,value)
    print("command set:".. key .. "  status:".. value)
    db[key] = value
    local last = db[key]
    return last
end

skynet.start(function()
    print("==================service start====================")
    skynet.dispatch("lua", function(session, address, cmd,...)
        local f = command[cmd]
        if f then
            -- 回应一个消息可以使用 skynet.ret(message, size) 。
            -- 它会将 message size 对应的消息附上当前消息的 session ,以及 skynet.PTYPE_RESPONSE 这个类别,发送给当前消息的来源 source 
            skynet.ret(skynet.pack(f(...))) --回应消息
        else
            error(string.format("Unknown command %s", tostring(cmd)))
        end
    end)

    --可以为自己注册一个别名。(别名必须在 32 个字符以内)
	skynet.register "SERVICE2"
end)
--main.lua
local skynet = require "skynet"

-- 启动服务(启动函数)
skynet.start(function()
	-- 启动函数里调用Skynet API开发各种服务
	print("======Server main start=======")
	-- skynet.newservice(name, ...)启动一个新的 Lua 服务(服务脚本文件名) 沙盒
	local service2 = skynet.newservice("service")

	-- 向service服务发出请求,设置game_0 = runing
	skynet.call(service,"lua","set","game_0","runing")	

	-- 向service服务发出请求,获取key1的值
	local game_status = skynet.call(service,"lua","get","game_0")

	print("service game_status : ",game_status)
	
	-- 退出当前的服务
	-- skynet.exit 之后的代码都不会被运行。而且,当前服务被阻塞住的 coroutine 也会立刻中断退出。
	skynet.exit()
end)

案例测试:

在这里插入图片描述

3、通信(server/client)

参考案例:官方的例子(test/testsocket.lua)

local skynet = require "skynet"
local socket = require "skynet.socket"

local clients = {}  --记录连接的客户端

-- 读取客户端消息 并输出
local function echo(id)
    -- 每当 accept 函数获得一个新的 socket id 后,并不会立即收到这个 socket 上的数据。这是因为,我们有时会希望把这个 socket 的操作权转让给别的服务去处理。
    -- 任何一个服务只有在调用 socket.start(id) 之后,才可以收到这个 socket 上的数据。
    socket.start(id)
    clients[id] = true
    while true do
        -- 读取客户端发过来的数据
        local str = socket.read(id)
        if str then
            -- 直接打印接收到的数据
            local _str = "[client".. id .. "] Send ".. str
            print(_str)

            for k,v in pairs(clients) do --广播
				socket.write(k, _str)
            end
            -- socket.write(id, _str)  --发给 客户端_id 接收的消息
        else
            socket.close(id)
            if clients[fd] then
                clients[fd] = nil
            end
            return 
        end
    end
end

skynet.start(function()
    print("==========Socket Start=========")
    -- 监听一个端口,返回一个 id ,供 start 使用
    local socket_id = socket.listen("127.0.0.1", 7777)
    print("Listen socket :", "127.0.0.1", 7777)

    socket.start(socket_id, function(id,addr)
        -- 接收到客户端连接或发送消息
        print("connect from" .. addr .. " [client ".. id .. " ]")

        -- 处理消息
        echo(id)
    end)
end)
--client.lua
package.cpath = "./skynet/luaclib/?.so"
package.path = "./skynet/lualib/?.lua;./test/service/?.lua"

local socket = require "client.socket"

local fd = assert(socket.connect("127.0.0.1", 7777))

socket.send(fd, "77777")
--main.lua
local skynet = require "skynet"

-- 启动服务(启动函数)
skynet.start(function()
	-- 启动函数里调用Skynet API开发各种服务
	print("======Server start=======")

	skynet.newservice("socket")
	skynet.exit()
end)
运行客户端:./skynet/3rd/lua/lua ./test/service/client.lua 

运行服务端:./skynet/skynet ./test/config

实例展示:

在这里插入图片描述

或者客户端:telnet 127.0.0.1 7777

在这里插入图片描述

4、Mysql连接

参考案例:官方的例子(test/testmysql.lua)

-- db test_db   创建测试数据库
create table msgs (
	id int not null auto_increment,
	client_id varchar(30) not null,
	content varchar(255) not null,
	primary key (id));

修改一下socket.lua 文件 将发言数据存到数据库

local skynet = require "skynet"
local socket = require "skynet.socket"
local mysql = require "skynet.db.mysql"

local clients = {}  --记录连接的客户端
local db = {}       --数据库连接

-- 读取客户端消息 并输出
local function echo(client_id)
    -- 每当 accept 函数获得一个新的 socket client_id 后,并不会立即收到这个 socket 上的数据。这是因为,我们有时会希望把这个 socket 的操作权转让给别的服务去处理。
    -- 任何一个服务只有在调用 socket.start(client_id) 之后,才可以收到这个 socket 上的数据。
    socket.start(client_id)
    clients[client_id] = true
    while true do
        -- 读取客户端发过来的数据
        local str = socket.read(client_id)
        if str then
            if str ==  "get\r\n" then
                --获取留言信息
                -- local _str = db:query("select * from msgs")
                -- for i,v in pairs(_str) do
                --     local content = "[client".. v.client_id .. "] : "..v.content.."\r\n"
				-- 	socket.write (client_id, content)
                -- end

                --获取留言信息
                local _str = db:query("select * from msgs")
                local content = "==========================留言版=========================\r\n"
                for i,v in pairs(_str) do
                    content = content .. "[client".. v.client_id .. "] : "..v.content.."\r\n"
                end
                content = content .. "==========================留言版=========================\r\n"
                socket.write (client_id, content)
            else

                -- 直接打印接收到的数据
                local _str = "[client".. client_id .. "] : ".. str
                print(_str)
                for k,v in pairs(clients) do --广播
                	socket.write(k, _str)
                end
                -- socket.write(client_id, _str)  --发给 客户端_client_id 接收的消息
                --留言存入数据库
                db:query("insert into msgs (client_id, content) values (\'"..client_id.."\',\'"..str.."\')")
            end
        else
            socket.close(client_id)
            if clients[fd] then
                clients[fd] = nil
            end
            return 
        end
    end
end

skynet.start(function()
    print("==========Socket Start=========")
    -- 监听一个端口,返回一个 client_id ,供 start 使用
    local socket_client_id = socket.listen("127.0.0.1", 7777)
    print("Listen socket :", "127.0.0.1", 7777)

    socket.start(socket_client_id, function(client_id,addr)
        -- 接收到客户端连接或发送消息
        print("connect from" .. addr .. " [client ".. client_id .. " ]")

        -- 处理消息
        echo(client_id)
    end)


    --连接数据库
    db = mysql.connect(
        {
            host = "127.0.0.1",
            port = 3306,
            database = "test_db",
            user = "root",
            password = "121212",
            max_packet_size = 1024 * 1024,
            on_connect = nil
        }
    )
end)

启动前数据库数据:

在这里插入图片描述

发信息后

在这里插入图片描述

数据库截图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/12583.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RK3399驱动开发 | 15 - RTC实时时钟芯片HYM8563S调试(基于linux5.4.32内核)

文章目录 一、Linux RTC设备驱动框架二、HYM8563实时时钟芯片1. 简介2. 引脚图3. 连接原理图三、设备驱动调试1. 设备树节点描述2. 使能内核驱动3. 测试四、hym8563驱动实现分析1. i2c设备驱动框架2. rtc设备注册流程3. 通过i2c驱动操作硬件一、Linux RTC设备驱动框架 Linux内…

宝塔防火墙必要的快速操作指令

重新启动、禁止固定ip等 重启firewall-cmd --reload 禁止固定ip:firewall-cmd --permanent --add-rich-rulerule family"ipv4" source address"192.168.1.1" reject 取消富规则:firewall-cmd --list-rich-rules 删除富规则&#…

Java#9(文字格斗游戏和对象数组练习)

目录 一.文字格斗游戏 二.对象数组 三.键盘录入练习 四.复杂对象数组练习 题目要求: 一.文字格斗游戏 Role类的代码 package Game;import java.util.Random;public class Role {String name;int blood;public Role() {}public Role(String name, int blood) {this.name na…

Node.js 流 Stream【详解】

什么是流? 流是一种将整体数据分割成多个小块依次进行处理的方式。 举个形象的例子: 山上有1000颗拳头大的小石子,需要搬下山。 传统的处理方式:安排一辆大卡车,一次性将石子全部运下山。流的处理方式:修…

Nginx制作下载站点

nginx使用的是模块ngx_http_autoindex_module来实现的,该模块处理以斜杠(“/”)结尾的请求,并生成目录列表。 nginx编译的时候会自动加载该模块,但是该模块默认是关闭的,使用下来指令来完成对应的配置 autoindex 启用或禁用目录…

医疗器械许可证怎么办理

医疗器械经营许可证申请条件 1.有两个与业务规模和业务范围相适应的质量管理机构或大专以上学历的质量管理人员。质量管理人员应具有国家认可的相关专业资格或职称; 2.具有与经营规模和范围相适应的相对独立的经营场所; 3.具备与经营规模和经营范围相…

解读OpenShift的逻辑架构和技术架构

01 OpenShift的逻辑架构 OpenShift的逻辑架构图如图2-6所示。 ▲图2-6 OpenShift逻辑架构 图2-6中的关键组件介绍如下。 底层基础设施:OpenShift可以运行在公有云(AWS、Azure、Google等)、私有云(OpenStack)、虚拟机(vSphere、RHV、红帽KVM)、X86、IBM Power/Z服务器上。…

跨域及cors解决跨域

1.什么是跨域 出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的…

DJ11 8086系列处理器(第二节课)

目录 一、8088CPU的系统总线 1. 最小模式 2. 最大模式 二、8086/8088 CPU 的功能结构 1. 8086/8088 CPU 的内部结构 2. 8086/8088 CPU 的内部寄存器 1)通用寄存器 2)段寄存器 3)控制寄存器 三、8086/8088 CPU 的存储器组织 1. 物…

超级账本Fabric的世界状态操作与账本操作

在 Hyperledger Fabric 中,账本由两个不同但相关的部分组成 - 世界状态和区块链。 世界状态: 一个数据库,其中存储了一组帐本状态的当前值的缓存。世界状态使程序可以轻松地直接访问状态的当前值,而不必通过遍历整个交易日志来计…

PROTAC与抗体偶联药物的结合

PROTAC 的靶点真核生物的蛋白降解途径主要分为溶酶体途径、泛素蛋白酶体途径、胞液蛋白酶水解途径和线粒体蛋白酶途径等四种 (图1)。其中,PROTAC 所依赖的蛋白酶体途径主要针对细胞周期蛋白、转录因子、细胞表面受体以及胞内变性蛋白等进行降解。 图 1. 不同蛋白降…

《安富莱嵌入式周报》第291期:分分钟设计数字芯片,单片机版JS,神经网络DSP,microPLC,FatFS升级至V0.15,微软Arm64 VS正式版发布

往期周报汇总地址:嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版: https://www.bilibili.com/video/BV1Dd4y1b74x 《安富莱嵌入式周报》第291期:分分…

分享几个小技巧教你图片怎么加边框

大家平时出去玩的时候,肯定没少拍摄照片吧?那你们都是怎么对图片进行修饰的呢?我比较喜欢给图片加上一些边框线条,这样子的图片会比较有意境,能凸显我想要表达的意思。那么大家知道怎么在图片里加边框吗?今…

【Vue.js设计与实现】第4章 响应系统的作用与实现

前言: 本文是我看的Vue.js设计与实现这本书第二篇 响应系统 的第4章 响应系统的作用与实现的一些总结与收获。 第4章从宏观视角讲述了Vue.js 3.0中响应系统的实现机制。从副作用函数开始,逐步实现一个完善的响应系统,还讲述了计算属性和watch…

java计算机毕业设计基于安卓Android的在线心理咨询与健康App

项目介绍 本文介绍了心理咨询与健康App软件开发建设的意义和国内外发展现状,然后详细描述了所开发手机APP的可行性分析,并分析了手机APP所要实现的功能。因为心里咨询设施较多,而且人口密集,不能更好的管理健康问题,造成需要时人员不必要的身心伤害,所以采用比较方便的、容易便…

Linux基本指令(下)

Linux基本指令(下)前言cat指令more命令less命令head命令tail命令wc指令date指令cal指令find指令grep指令top命令alias命令zip/unzip命令前言 上一篇Linux基本指令主要讲解了关于文件操作方面的指令,接下来这一片Linux基本指令主要讲解一下关…

聊聊推荐系统的评测(下)

这是鼎叔的第三十九篇原创文章。 行业大牛和刚毕业的小白,都可以进来聊聊。 欢迎关注本人专栏和微信公众号《敏捷测试转型》,大量原创思考文章陆续推出。 上篇请查阅:聊聊推荐系统的评测(上) 下篇,我们…

基于SSM的旅游景点购票管理系统

1、项目介绍 基于SSM的旅游景点购票管理系统拥有两种角色,管理员和用户 管理员:用户管理、景点管理、购票管理、酒店管理、客房管理、客房预订管理、轮播图管理等 用户:登录注册、景区购票、评论、预订客房、收藏、发布攻略等 2、项目技术…

App推广渠道追踪技术更新及应用

如今App推广渠道追踪对App厂商来说非常重要,因为App厂商需要通过渠道追踪来寻找成本最低的和价值最高的获客渠道。 但是现在线上渠道的选择五花八门,比如各种新闻门户网站、字节系平台、腾讯系平台等,那么到底该花多少钱去获取用户&#xff…

本地浏览器打开远程服务器上的Jupyter Notebook

文章目录一、配置过程二、其他需求后台运行Jupyter端口映射实验环境及需求:远程服务器配置了 Jupyter Notebook,本地电脑没有相关的环境,想要在服务器端启动 Jupyter Notebook,然后直接从本地浏览器打开进行操作。 一、配置过程 …