Lua教程
Lua语言简介
Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
Lua 是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组于 1993 年开发的,该小组成员有:Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo。
设计目的
其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
轻量级
Lua编译后仅仅一百余K,可以很方便的嵌入别的程序里。
Lua应用场景
- 游戏开发
- 独立应用脚本
- Web 应用脚本
- 扩展和数据库插件如:MySQL Proxy 和 MySQL WorkBench
- 安全系统,如入侵检测系统
安装Lua
curl -L -R -O https://www.lua.org/ftp/lua-5.4.8.tar.gz
tar zxf lua-5.4.8.tar.gz
cd lua-5.4.8
make all test
sudo make install
lua 数据分为值类型和引用类型。值类型可以直接复制,比如整数,浮点数等。而引用类型共享同一份数据,由 GC 维护生命周期,比如,table,string 等。
Lua与C混合编程
The following example implements an HTTP server in C and Lua that listens on port 8080 and supports file uploads, you can combine the low-level power of C with the flexibility of Lua for scripting.
C: Handles the low-level socket programming for the HTTP server.
Lua: Handles the parsing of HTTP requests and the file upload logic.
C Code: Low-Level HTTP Server
The following C code sets up a simple HTTP server that listens on port 8080 and forwards HTTP requests to a Lua handler script.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#define PORT 8080
#define BUFFER_SIZE 4096
void error(const char *msg) {
perror(msg);
exit(1);
}
void handle_request(int client_socket) {
char buffer[BUFFER_SIZE];
int bytes_read = recv(client_socket, buffer, sizeof(buffer) - 1, 0);
if (bytes_read < 0) {
error("Error reading from socket");
}
buffer[bytes_read] = '\0';
// Load Lua
lua_State *L = luaL_newstate();
luaL_openlibs(L);
// Pass the HTTP request to Lua
lua_getglobal(L, "process_request");
lua_pushstring(L, buffer);
if (lua_pcall(L, 1, 1, 0) != 0) {
fprintf(stderr, "Lua error: %s\n", lua_tostring(L, -1));
lua_close(L);
close(client_socket);
return;
}
// Get the Lua response
const char *response = lua_tostring(L, -1);
send(client_socket, response, strlen(response), 0);
lua_close(L);
close(client_socket);
}
int main() {
int server_socket, client_socket;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
// Create socket
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
error("Error opening socket");
}
// Bind socket
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
error("Error on binding");
}
// Listen for connections
listen(server_socket, 5);
printf("Server is running on port %d...\n", PORT);
while (1) {
client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_len);
if (client_socket < 0) {
error("Error on accept");
}
handle_request(client_socket);
}
close(server_socket);
return 0;
}
Lua Script: HTTP Parsing and File Upload Handling
The Lua script processes the HTTP request, including parsing headers and handling file uploads.
-- Save this file as "server.lua"
local function parse_headers(request)
local headers = {}
for line in request:gmatch("[^\r\n]+") do
local key, value = line:match("^(.-):%s*(.+)$")
if key and value then
headers[key:lower()] = value
end
end
return headers
end
local function save_file(filename, content)
local file = io.open(filename, "wb")
file:write(content)curl -X POST -F "file=@test.txt" http://localhost:8080
file:close()
end
local function parse_multipart_body(body, boundary)
local files = {}
for part in body:gmatch("--" .. boundary .. "(.-)--" .. boundary .. "--") do
local disposition = part:match("Content%-Disposition:%s*form%-data;%s*name=\"(.-)\";%s*filename=\"(.-)\"")
if disposition then
local filename, content = part:match("filename=\"(.-)\".-\r\n\r\n(.*)")
if filename and content then
table.insert(files, { filename = filename, content = content })
end
end
end
return files
end
function process_request(request)
local method, path, version = request:match("^(%w+)%s+(%S+)%s+(HTTP/%d%.%d)")
local headers = parse_headers(request)
local body = request:match("\r\n\r\n(.*)")
if method == "POST" and headers["content-type"]:find("multipart/form-data") then
local boundary = headers["content-type"]:match("boundary=(.+)")
local files = parse_multipart_body(body, boundary)
for _, file in ipairs(files) do
save_file(file.filename, file.content)
end
return "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nFile uploaded successfully!"
end
return "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\n\r\nResource not found!"
end
编译
gcc -o http_server http_server.c -llua -lm
运行
./http_server
测试
curl -X POST -F "file=@test.txt" http://localhost:8080