6.3. 你的第一个 Pike 脚本

Pike 脚本非常像 Perl 脚本。当用户尝试访问它时,它会被执行。因此,Pike 脚本通常是你公共 Web 文件所在的位置。如果你已经有 Perl 背景并想尝试 Pike,这是一个不错的选择。

在这样做时,你有两种选择。你可以将 Pike 作为 CGI 脚本执行,或者在服务器内部执行。如果你不知道什么是 CGI,请在 http://www.tldp.org/ 查看 Apache-Overview-HOWTO。

在这里,我们将在 Caudium 内部运行 Pike 脚本。要实现这一点,你必须通过选择在你的服务器中加载另一个模块加载模块CIF 中。现在你有了 Caudium 中所有可用模块的列表。正如你所看到的,有很多模块,阅读此页面应该会给你一些未来开发的想法。要选择 Pike 脚本模块,只需单击名为 “Pike script support” 的图像(如果你使用图形浏览器)。

现在你可以创建一个包含例如以下内容的 .pike 文件,

示例 6-3. 一个基本的 Pike 脚本。

// you have to inherit caudiumlib to have some basic things
// like the id object and response mapping
inherit "caudiumlib";

// the same as the main
// if you modify this script and you see that Caudium don't take your
// modification into account, reload the Pike script support module
// This is because Caudium uses a cache for performance reasons
string parse(object id)
{
  string html = "<html><body>The id object contain some "
  "very useful information<br />";
  html += sprintf("The id->variables contain a list of "
  "arguments given to this script %O\n", id->variables);
  return html;
}  
      

Pike 脚本通常用于小型内部开发。在这种情况下,Pike 脚本非常有用,因为你可以用很少的行创建一些东西。这是一个此类脚本的示例

示例 6-4. 一个真实世界的脚本。

/* Here is a Pike script (not a Caudium module).
   This script is less than 20 lines (comments
   and blank lines excluded) and will randomly
   return one file to the web browser from a list of files.
   This script was kindly provided by Xavier Beaudouin */

// first we need to inherit from caudiumlib in order to get
// the parse, http_redirect functions and id object
// recognized.
inherit "caudiumlib";

// we declare an array of files
array (string)files;

// an ASCII text containing the name of a file
// on the real filesystem.
// Each file name in this file will be
// randomly return (the files name have to be on
// a separate line).
#define FILELIST "/list"

#define BASEDIR "/thepath2yourfiles/"

// this function is the constructor, it will be loaded first
void create () {
 // the array of strings 'files' will contain
 // all the files we serve provided the file
 // FILELIST list each file name on one line.
 files = Stdio.read_bytes(FILELIST)/"\n";
}

// if no_reload return 1, Caudium will cache the
// result of this script for maximum performances
// and will not execute it a second time.
// As a result, If you give the argument 
// ?reload=1 to your script, Caudium will 
// reload it. 
// This is useful to use cache for average
// content delivery unless you are doing
// developpement
int no_reload(object id)
{
 if(!id->variables->reload)
   return 1;
 return 0;
}

// As this is a simple pike script (CGI like), this function
// will be called by Caudium and should return a string that
// will be display to the client's browser.
// It can also return a mapping containing all the HTTP response
// (headers + text)
mapping parse(object id)
{
 // We randomly return one of the file we list in the FILELIST file
 // (relative to BASEDIR directory).
 // http_redirect will send a HTTP 301 header telling the browser
 // where to get randomly selected file.
 return http_redirect(BASEDIR + files[random(sizeof(files))],id);
}
      

但你也可以创建一些强大的脚本

示例 6-5. 一个为高级用户准备的脚本。

inherit "caudiumlib";

string|mapping|object parse( object id )
{
  id->my_fd->write(id->clientprot + " 200 Ok\r\n");
  id->my_fd->write("Server: Caudium !\r\n");
  id->my_fd->write("Expires: 0\r\n");
  id->my_fd->write("Content-Type: text/html\r\n");
  id->my_fd->write("pragma: no-cache\r\n\r\n");
  id->my_fd->set_id( ({ id->my_fd }) );
  id->my_fd->set_nonblocking(0,send_data);
  return http_pipe_in_progress();
}

void send_data(array (object) id)
{

  id[0]->write("<pre>");
  id[0]->write("test......................\n");
  id[0]->write("test......................\n");
  id[0]->write("test......................\n");
  id[0]->write("sleep for 10 sec\n");
  sleep(10);
  id[0]->write("Done</pre>");
  id[0]->close();
  destruct(id[0]);
}
      

此示例使用非阻塞套接字。 my_fd 是 HTTP 套接字的文件描述符。这里我们将 HTTP 套接字的类型从阻塞套接字(默认类型)更改为非阻塞套接字。非阻塞套接字是不会阻塞程序等待数据的套接字。相反,当有数据要读取或写入 HTTP 套接字时,将自动调用一个readwrite函数(所谓的回调函数)。此外,我们在这里返回一个特殊的函数,http_pipe_in_progress。这是因为由于 HTTP 套接字设置为非阻塞,Caudium 将无法等待处理 HTTP 内容,例如标头等等。所以我们必须告诉它不要等待我们并发送一个http_pipe_in_progress.

当你必须在单进程服务器(多线程服务器)上与慢速套接字进行一些通信时,这种机制非常有用。在单进程的情况下,当你等待一个套接字时,整个服务器都会等待。因此,你的所有用户都会被停滞。使用非阻塞套接字,不再有任何问题;服务器不会等待每个套接字。此类代码的示例包括 CAMAS IMAP/NNTP 客户端。如果你不理解,请不要担心,你通常不必理解这些机制。

但是,尽管 Pike 脚本允许你编写一些复杂的代码,但它不太适合大型项目。如果是这种情况,请阅读下一段并享受。

Note

Caudium API 在 http://caudium.net/ 上可用。你还应该阅读 http://caudium.info/ 上的 Roxen 1.3 PDF。Pike 脚本是阻塞的,并允许你的用户以与服务器相同的权限运行脚本。阻塞意味着如果来自 pike 脚本的套接字被停滞(通常是等待某些东西),服务器将被停滞。即使你在脚本中使用非阻塞套接字,这也适用。使用模块你不会遇到这个问题。