python代码
import socket
import struct
import threading
# FastCGI 头格式(8 字节)
FCGI_HEADER_FORMAT = "!BBHHBx"
FCGI_VERSION = 1
FCGI_TYPE_BEGIN_REQUEST = 1
FCGI_TYPE_PARAMS = 4
FCGI_TYPE_STDIN = 5
FCGI_TYPE_STDOUT = 6
FCGI_TYPE_END_REQUEST = 3
FCGI_RESPONDER = 1
def parse_fcgi_header(data):
"""解析 FastCGI 头"""
version, type_, request_id, content_length, padding_length = struct.unpack(FCGI_HEADER_FORMAT, data)
return version, type_, request_id, content_length, padding_length
def read_fcgi_record(client_socket):
"""读取并解析 FastCGI 记录"""
header = client_socket.recv(8) # 读取 8 字节头部
if not header:
return None, None, None, None, None
version, type_, request_id, content_length, padding_length = parse_fcgi_header(header)
content = client_socket.recv(content_length) if content_length > 0 else b""
client_socket.recv(padding_length) # 读取并丢弃填充数据
return type_, request_id, content, content_length, padding_length
def parse_fcgi_params(data):
"""解析 FastCGI PARAMS(key-value 形式)"""
params = {}
i = 0
while i < len(data):
name_length = data[i]
value_length = data[i + 1]
i += 2
# 处理长度值大于 127 的情况
if name_length >= 128:
name_length = ((name_length & 0x7F) << 24) | (data[i] << 16) | (data[i+1] << 8) | data[i+2]
i += 3
if value_length >= 128:
value_length = ((value_length & 0x7F) << 24) | (data[i] << 16) | (data[i+1] << 8) | data[i+2]
i += 3
name = data[i : i + name_length].decode("utf-8", errors="ignore")
value = data[i + name_length : i + name_length + value_length].decode("utf-8", errors="ignore")
params[name] = value
i += name_length + value_length
return params
def handle_request(client_socket):
"""处理 FastCGI 请求"""
try:
# 读取 BEGIN_REQUEST 记录
type_, request_id, content, _, _ = read_fcgi_record(client_socket)
if type_ != FCGI_TYPE_BEGIN_REQUEST:
client_socket.close()
return
# 读取所有 PARAMS(FastCGI 请求参数)
params_data = b""
while True:
type_, _, content, content_length, _ = read_fcgi_record(client_socket)
if type_ != FCGI_TYPE_PARAMS or content_length == 0:
break # 读取完成
params_data += content
# **使用修正的解析函数**
param_dict = parse_fcgi_params(params_data)
print("Received FCGI Params:", param_dict)
# 读取 STDIN(HTTP 请求体)
stdin_data = b""
while True:
type_, _, content, content_length, _ = read_fcgi_record(client_socket)
if type_ != FCGI_TYPE_STDIN or content_length == 0:
break
stdin_data += content
# 生成 HTTP 响应
response_body = b"Hello, FastCGI over TCP! (Threaded)"
response_headers = b"Content-Type: text/plain\r\nContent-Length: %d\r\n\r\n" % len(response_body)
stdout_data = response_headers + response_body
# 发送 FastCGI 响应
stdout_header = struct.pack(FCGI_HEADER_FORMAT, FCGI_VERSION, FCGI_TYPE_STDOUT, request_id, len(stdout_data), 0)
end_header = struct.pack(FCGI_HEADER_FORMAT, FCGI_VERSION, FCGI_TYPE_END_REQUEST, request_id, 0, 0)
client_socket.sendall(stdout_header + stdout_data) # 发送正文
client_socket.sendall(end_header) # 发送结束标志
except Exception as e:
print(f"Error handling request: {e}")
finally:
client_socket.close()
def start_fcgi_server(host="0.0.0.0", port=9000):
"""启动 FastCGI 多线程 TCP 服务器"""
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((host, port))
server_socket.listen(5)
print(f"FastCGI Server listening on {host}:{port}")
while True:
client_socket, _ = server_socket.accept()
thread = threading.Thread(target=handle_request, args=(client_socket,))
thread.start() # 启动新线程处理请求
if __name__ == "__main__":
start_fcgi_server()
nginx添加配置
location /hello {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
# 传递 FastCGI 相关参数
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param SCRIPT_FILENAME /dummy;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param PATH_INFO $fastcgi_script_name;
}
访问结果