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 examples\PingpongServer.lua,然后執行 Joynet examples\PingpongClient.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("\r\n")
--讀取多行頭部
while true do
packet = session:receiveUntil("\r\n")
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\r\nConnection: close\r\nContent-Type: text/html\r\nContent-Length: "..string.len(htmlBody).."\r\n\r\n"..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
