伟明部落格

Lua教程

发布于 2025-10-09 22:55:56

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 维护生命周期,比如,tablestring 等。

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
更新于 2025-10-25 15:56:18