Joynet
项目地址:https://github.com/IronsDu/Joynet
介绍
high performance network library for lua, based on https://github.com/IronsDu/accumulation-dev and lua coroutine. Joynet 的网络底层使用多线程,但Lua (层面)是运行在单线程上。
借助协程提供同步形式的API。(同步的socket api,同步的http api,同步的redis api)
让应用业务开发更轻松,更爽!
src 目录是此项目源代码, libs 目录为基于此Lua协程网络库开发的一些库
构建
- Windows : 在项目根目录中打开 Joynet.sln, 编译即可在当前目录产生可执行文件 Joynet
- Linux : 在项目根本执行
make即可生成可执行文件 Joynet
使用
examples 包含测试代码。 譬如我们要在Windows下运行PingPong测试: 先在项目根目录执行 Joynet examplesPingpongServer.lua,然后执行 Joynet examplesPingpongClient.lua
一个小问题
当前Joynet是作为一个宿主程序,由其运行业务Lua文件。 不过我们能轻松的把它作为动态库集成到已有的应用系统里。
关于协程
协程是轻量级线程,所以多线程有的问题它也有,只是影响程度不同。 在协程中使用同步API会阻塞当前协程,所以当你的应用程序只有一个协程从外部收取网络消息时,且在消息处理中使用同步API 操作Redis或者Http的话,效率会很低。 这时有两个方案可解决:1 、提供回调形式的异步API, 但这样会使开发概念混乱 ; 2、 在前面说到的情景的消息处理中开启协程,并在其中操作HTTP/Redis,而不是直接在消息处理所在协程中进行操作。 (当然,协程的创建和切换有一定开销,所以~看着办吧 ^-^ )
例子:
PingpongServer.lua:
package.path = "./src/?.lua;./libs/?.lua;"
local TcpService = require "TcpService"
local AcyncConnect = require "Connect"
local totalRecvNum = 0
function userMain()
--开启服务器
local serverService = TcpService:New()
serverService:listen("0.0.0.0", 9999)
coroutine_start(function()
while true do
local session = serverService:accept()
if session ~= nil then
coroutine_start(function ()
local strLen = 5 --读取5个字节
while true do
local packet = session:receive(strLen)
if packet ~= nil then
totalRecvNum = totalRecvNum + 1
session:send(packet)
end
if session:isClose() then
break
end
end
end)
end
end
end)
coroutine_start(function ()
while true do
coroutine_sleep(coroutine_running(), 1000)
print("total recv :"..totalRecvNum.."/s")
totalRecvNum = 0
end
end)
end
coroutine_start(function ()
userMain()
end)
while true
do
CoreDD:loop()
while coroutine_pengdingnum() > 0
do
coroutine_schedule()
end
end
PingPongClient.lua:
package.path = "./src/?.lua;./libs/?.lua;"
local TcpService = require "TcpService"
local AcyncConnect = require "Connect"
local totalRecvNum = 0
function userMain()
--开启10个客户端
local clientService = TcpService:New()
clientService:createService()
for i=1,1 do
coroutine_start(function ()
local session = clientService:connect("127.0.0.1", 9999, 5000)
if session ~= nil then
local str = "hello"
local strLen = string.len(str)
session:send(str)
while true do
local packet = session:receive(strLen)
if packet ~= nil then
totalRecvNum = totalRecvNum + 1
session:send(packet)
end
if session:isClose() then
break
end
end
else
print("connect failed")
end
end)
end
coroutine_start(function ()
while true do
coroutine_sleep(coroutine_running(), 1000)
print("total recv :"..totalRecvNum.."/s")
totalRecvNum = 0
end
end)
end
coroutine_start(function ()
userMain()
end)
while true
do
CoreDD:loop()
while coroutine_pengdingnum() > 0
do
coroutine_schedule()
end
end
Http Server :
package.path = "./src/?.lua;./libs/?.lua;"
local TcpService = require "TcpService"
local totalRecvNum = 0
function userMain()
if true then
--开启http服务器
local serverService = TcpService:New()
serverService:listen("0.0.0.0", 80)
coroutine_start(function()
while true do
local session = serverService:accept()
if session ~= nil then
coroutine_start(function ()
--读取报文头
local packet = session:receiveUntil("
")
--读取多行头部
while true do
packet = session:receiveUntil("
")
if packet ~= nil then
if #packet == 0 then
--print("recv empty line")
break
end
end
end
local htmlBody = "<html><head><title>This is title</title></head><body>hahaha</body></html>"
local response = "HTTP/1.1 200 OK
Connection: close
Content-Type: text/html
Content-Length: "..string.len(htmlBody).."
"..htmlBody
session:send(response)
totalRecvNum = totalRecvNum + 1
end)
end
end
end)
coroutine_start(function ()
while true do
coroutine_sleep(coroutine_running(), 1000)
print("total recv :"..totalRecvNum.."/s")
totalRecvNum = 0
end
end)
end
coroutine_start(function ()
userMain()
end)
while true
do
CoreDD:loop()
while coroutine_pengdingnum() > 0
do
coroutine_schedule()
end
end