SCGI = Simple CGI

SCGI的产生

传统意义上的CGI程序,由Web Server在接收到客户端请求时,启动相应的程序。

这里主要有两个问题:

  • CGI程序由Web服务器启动,两者之间的耦合较为紧密。
  • CGI程序的启动是比较耗费系统资源的。

随后的FastCGI采用下面的方案来改进问题:

  • FastCGI自身作为服务器接受来自Web服务器的请求。
    • 这做到了与Web服务器的解耦。
  • FastCGI自身提供相应的Web服务。
    • 这避免了频繁启动外部程序的开销。

但是FastCGI的协议相对复杂。于是有了SCGI的产生。

SCGI协议概要

一个CGI请求,主要是传递相关的环境变量,和请求数据;其响应可以简单的输出结果就可以。

SCGI的协议可以概括为

  1. Web服务器向后端的SCGI服务建立连接。
  2. Web服务器向SCGI服务发送请求。
  3. SCGI服务接收请求,将相应响应数据发回Web服务器。
  4. SCGI服务最后关闭当前连接。

其中的请求部分内容概括如下:

  • [format "%s\0%s\0" $name $value]来编码请求头中的字段
  • 所用请求头中的字段合起来组成请求头
    • 第一个字段必须是CONTENT_LENGTH
    • SCGI字段是必须的
  • 全部请求头用netstring格式进行编码
  • 最后在附上请求数据的内容。

SCGI协议的代码示意

set header [dict create]
dict set header CONTENT_LENGTH [string length $body]
dict set header SCGI 1
dict set header ...

set request ""
dict for {name value} $header {
  append request "$name\0$value\0"
}

set request [netstring $request]
append request $body

set sock [socket $scgi_host $scgi_port]
write $sock $request
set response [read $sock]
close $sock

netstring编码

proc netstring {bytes} {
  return [format "%d:%s," [string length $bytes] $bytes]
}

上面代码中的$bytes是二进制数据流。这意味着,实际程序中需要进行字符串编码转换。