前端时间需要一个嵌入式的webserver,但最终没有一个比较满意的。
最近就在想是否自己写一个支持lua脚本的服务器版本,可以嵌入到各种webserver中,且是与webserver集成在一起,而非单独进程方式(类似cgi)。
想到那么就开始动手写,由于之前利用的是cgilua,那么就做一个cgilua的子集吧,尽量兼容。
需求
- 兼容cgilua,其网页格式仍然以.lp为后缀
- lp文件格式通cgilua
- 尽量做到少依赖其他库或者文件(比如说SAPI,expact等)
- 文件尽量少,可以方便的在linux,windows,uclinux,vxworks下移植和使用
- 不创建新的进程/Task来处理lp
- 暂不支持sajax
基本思路
- 读取lp文件,并解释成LUA语法。将HTML语句转换cgilua.put语句,去掉LUA语句前后的转义字符
- 调用LUA虚拟机执行lua语句,将结果通过webserver发送出去
- webserver在适配代码中需要将POST信息,环境变量等信息传递给lua虚拟机,传递方式就是创建相应的POST和env数组
代码结构
代码主要分为两部分,一部分为实现lp文件解析,另一部分为与webserver之间的适配代码。
- sluacgi.c、lua.c为lp解析文件
- mongoose.c为webserver代码和适配代码(可与mongoose源码比较,新增代码为适配代码)
- main.c
选择mongoose的缘故是因为mongoose可以在windows下运行,方便调试
接口
对外接口
- lp_load: 加载文件,并解释成lua语法。对应与lp_load_free,释放lp_load所申请的资源
- lp_parse:启动LUA虚拟机,执行lua脚本,最后得到所需的html语句。对应与lp_parse_free,释放lp_load所申请的资源
webserver需要实现接口
- sluacgi_make_env: html需要的环境变量,实现类似cgilua的servervariable接口
- sluacgi_make_args: 生成POST信息
- sluacgi_post_savefile: POST文件保存接口(针对post文件,为了减少内存消耗,与cgilua实现不一样)
兼容cgilua接口列表
- put
- servervariable
- header
- httpstatus
- lp.include
- mkurlpath
- mkabsoluteurl
- splitonlast
- splitonfirst
可优化
- 如果是用于嵌入式系统上,建议采用thttpd,因为其完全是用单线程做处理,效率和资源使用更高效
- 如果是单线程处理,则对lp_load和lp_parse可做下优化处理,不需要频繁申请/释放内存
- 如果不需要支持 #!/usr/bin/env cgilua.cgi ,建议将lp_load中对lp_check_exec调用去掉,更高效一些
- 目前暂不支持sajax,如果需要可直接加入
代码
http://download.csdn.net/source/2662100
lp文件格式
普通
请参考附件中的例子
文件
为了兼容cgilua,故写成如下格式
<html>
<% cgilua.lp.include ("header.lp")%><tr align="center" bgcolor="#CCCCCC">
<td width="472" height="44" colspan="2"><div align="center">
<p><font color="#0" size="4" face="Geneva, Arial, Helvetica, sans-serif"><strong>demo</strong></font></p>
</div></td>
</tr><form method="POST" enctype="multipart/form-data" action="admin_soft_update.lp">
<tr bgcolor="#888888">
<td>file</td>
<td>
<input type="file" name="file">
</td>
</tr><tr bgcolor="#CCCCCC">
<td height="20" colspan="2" align="center"><div align="right">
<input type="submit" value="put">
</div></td>
</tr>
</form>
<%
local fs_dir = 'www/uploads/'
local msg = nillocal function xavante_save()
local f = cgilua.POST.file
if f and next(f) then
local _, name = cgilua.splitonlast(f.filename)
local file1 = f.file
os.execute('rm -rf '..fs_dir..'*')
os.execute('mkdir '..fs_dir)
local dest = io.open(fs_dir..name, "wb")
if dest then
local bytes = file1:read("*a")
dest:write(bytes)
dest:close()
end
return true, name
end
return false
endlocal function sluacgi_save()
local filename = cgilua.POST.filename
if filename then
local _, name = cgilua.splitonlast(filename)
os.execute('rm -rf '..fs_dir..'*')
os.execute('mkdir '..fs_dir)
cgilua.savefile(fs_dir..name)
return true, name
end
return false
endfunction save_file()
if cgilua.sluacgi_ver then
return sluacgi_save()
else
return xavante_save()
end
endlocal ret, name = save_file()
if ret then
msg = 'success'
else
msg = 'failure'
end
%></table>
<p>this is a demo</p>
<% cgilua.lp.include ("buttom.lp")%></table>
</form>
</center><script language="javascript">
<%
if( msg ) then
cgilua.put("alert('"..msg.."')")
end
%>
</script>
</body>
</html>
工程文件说明
源码中用到了lua和tolua++的第三方库,下载地址为:
lua: http://www.lua.org/download.html
tolua++: http://www.codenix.com/~tolua/
下载下来后解压放入sluacgi目录, 然后修改mongoose项目属性的中的addtational include Directories 中的包含路径,编译即可