【问题标题】:Multiple CGI Perl scripts多个 CGI Perl 脚本
【发布时间】:2016-08-30 12:48:50
【问题描述】:

这是一个理论问题。我正在尝试开发基于生产者-消费者范式的 Perl 应用程序。其中一个脚本创建一个包含数据的文件,而另一个脚本读取数据并以 HTML 格式呈现。还有第三个文件,一个 HTML 表单,用于启动生产者 perl 文件。

我不知道如何使用 CGI 同时运行生产者和消费者,我在网上找不到有关它的信息(至少不是我搜索的方式为它)。

我想知道您能否告诉我在哪里可以找到此类信息,以便我可以在 Apache 服务器中测试应用程序。

提前致谢

【问题讨论】:

  • 如果您担心关注点分离,请不要使用 CGI。观看this lightning talk,然后使用 PSGI/Plack 网络框架。它更现代,更易于实施和维护,并且您仍然可以进行分离。关键是你使用生产和消费的模块分开。然后将它们捆绑在一个应用程序中。如果您仍然希望它是 CGI,请将这些模块捆绑在一个 CGI 脚本中。但不要尝试做多个程序。这将是地狱般的设置和维护。这不是事情的完成方式。
  • @simbabque,我同意 CGI 是过时的技术(顺便感谢视频),但我认为我的问题不能仅通过接近 CGI 来解决,而是 HTML 表单和Perl 脚本。我只是想知道是否有一种方法可以同时启动两个脚本。 HTML 表单只启动生产者,因为我只能用一个 URL 填充 标记,但是有没有办法也启动另一个脚本?
  • 不,没有。仅当您将它们放在单个入口点后面时。本质上,将它们变成模块。或者制作一个分叉到一个的脚本,等待它完成,然后再分叉到另一个。但这将(用 Sawyer 的话来说)确实需要双重手套。 ;)
  • 我想说的是,您可以拥有一个服务于所有事物的单一入口点,包括 HTML。那可以是一个 CGI 应用程序,但它也可以是一个 PSGI 应用程序。无论如何,一个 Web 请求触发两个进程,一个等待另一个完成然后发送响应的想法是错误的。网络不是那样工作的。如果您坚持使用模式,请改用 MVC。
  • 您需要一项功能来存储数据。您需要另一个功能来查看存储的数据。为什么不使用某种数据库?然后你的数据库引擎可以处理所有关于文件锁定、并发访问等的棘手问题。SQLite 可能是合适的。

标签: perl cgi


【解决方案1】:

免责声明:我认为这个问题归结为如何让程序的两个不同组件相互交互以创建一个可从 Web 访问的应用程序。如果这不是您想要的,请将其视为深思熟虑。

通用网关接口

您在问题中谈论的是 CGI 脚本。 (强调我的)。

我正在尝试开发一个基于生产者-消费者范式的 Perl 应用程序。其中一个脚本创建一个包含数据的文件,而另一个则读取数据并以 HTML 的形式呈现。

一般来说,CGI 的工作方式是请求通过 Web 服务器,然后传递给应用程序。该应用程序可能是用 Perl 编写的。如果它是 Perl 脚本,则该脚本由 perl 解释器运行。 Web 服务器启动该过程。它可以通过CGI访问请求信息,主要是环境变量。该过程完成后,它将数据写入 STDOUT,Web 服务器将其作为响应并发回。

+-----------+        +-------------+                     +----------------+
|           | +----> |             | +-----Request-----> |                |
|  Browser  |        | Web server  |                     |  perl foo.cgi  |
|           | <----+ |             | <-----Response----+ |                |
+-----------+        +-------------+                     +----------------+

现在因为 Web 服务器后面只涉及一个进程,所以您不能有两个脚本。服务器无法同时与两个事物进行通信。这不是 CGI 的工作原理。

综合方法

相反,您需要将两个脚本包装到一个入口点,并将它们转换为某种组件。然后您可以让它们在内部相互通信,而在外部,Web 服务器只等待一个程序完成。

+-----------+        +-------------+                     +-----------------+
|           | +----> |             | +-----Request-----> |                 |
|  Browser  |        | Web server  |                     |  perl foo.cgi   |
|           | <----+ |             | <-----Response----+ |                 |
+-----------+        +-------------+                     | +-------------+ |
                                                         | |  Producer   | |
                                                         | +-----+-------+ |
                                                         |       |         |
                                                         |       |         |
                                                         |       V         |
                                                         | +-------------+ |
                                                         | | Consumer    | |
                                                         | +-------------+ |
                                                         |                 |
                                                         +-----------------+

要将其翻译成 Perl,我们首先要确定一些术语。

  • 脚本:一个位于 .pl 文件中且没有自己的 package 的 Perl 程序
  • module:一个 Perl 模块,它位于 .pm 文件中,并且有一个 package 和一个适合文件名的命名空间

假设您有这两个 Perl 脚本,我们称之为 producer.plconsumer.pl。它们被大大简化,不考虑任何参数。

producer.pl

#!/usr/bin/perl
use strict;
use warnings 'all';
use CGI;

open my $fh, '>', 'product.data' or die $!;
print $fh "lots of data\n";
close $fh;

consumer.pl

#!/usr/bin/perl
use strict;
use warnings 'all';
use CGI;

my $q = CGI->new;
print $q->header('text/plain');

open my $fh, '<', 'product.data' or die $!;
while my $line (<$fh>) {
    print $line;
}

exit;

这是尽可能简化的。有一个创建数据的脚本和一个使用它的脚本。现在我们需要让这两个交互而不实际运行它们。

让我们继续假设我们已经重构了这两个脚本并将它们转换为模块。我们稍后会看到它是如何工作的。我们现在可以在新的 foo.pl 脚本中使用这些模块。它将处理请求,向生产者请求数据,并让消费者将数据转换为读者想要的格式。

foo.pl

#!/usr/bin/perl
use strict;
use warnings 'all';
use Producer; # this was producer.pl
use Consumer; # this was consumer.pl
use CGI;

my $q = CGI->new;

my $params; # those would come from $q and are the parameters for the producer

my $product = Producer::produce($params);
my $output = Consumer::consume($product);

print $q->header;
print $output;

exit;

这很简单。我们从 CGI 读取参数,将它们传递给生产者,然后将产品传递给消费者。这给了我们输出,我们将其打印出来,然后返回到服务器,服务器发送响应。

让我们看看我们如何将这两个脚本变成简单的模块。那些不需要是面向对象的,尽管这可能是首选。请注意,文件名的拼写现在不同了。模块名称通常以大写字母开头。

Producer.pm

package Producer;
use strict;
use warnings 'all';

sub produce {
    my @args = @_;

    return "lots of data\n";
}

1;

Consumer.pm

package Consumer;
use strict;
use warnings 'all';

sub consume {
    my ($data) = @_;

    return $data; # this is really simple
}

1;

现在我们有两个模块,如果您调用正确的函数,它们的作用与脚本相同。我所做的只是在顶部放置一个命名空间 (package) 并将代码包装在 sub 中。我还删除了 CGI 部分。

在我们的示例中,生产者不必写入文件。它可以只返回数据结构。消费者反过来不需要从文件中读取。它只需要一个带有数据结构的变量并对其进行处理以呈现它。

如果您坚持使用一致的函数名称(例如 produceconsume,会更好),您甚至可以编写多个生产者或消费者。我们这里基本上定义了一个接口。这使我们有可能在不破坏兼容性的情况下重构代码的内部结构,而且还可以坚持完全不同的生产者或消费者。您可以从单行字符串生成器切换到在心跳中查找数据库中的内容的生成器,只要您坚持您的界面。

本质上,我们刚才所做的也可以这样显示:

+--foo.pl---------------------------+
|                                   |
|  +------+        +-------------+  |
|  |      | +----> |             |  |
|  |      |        |  Producer   |  |
|  |      | <----+ |             |  |
|  | main |        +-------------+  |
|  | foo  |                         |
|  | body |        +-------------+  |
|  |      | +----> |             |  |
|  |      |        |  Consumer   |  |
|  |      | <----+ |             |  |
|  +------+        +-------------+  |
|                                   |
+-----------------------------------+

这可能看起来有点眼熟。它本质上是Model-View-Controller (MVC) 模式。在 Web 上下文中,模型和视图通常只通过控制器相互通信,但几乎相同。

我们的生产者是一个数据模型。消费者将数据变成用户可以看到的网站,所以它是 view。 foo.pl 中将它们粘合在一起的主程序控制数据流。它是控制器

触发整个事情的初始网站可以是程序的一部分,如果没有传递参数则显示,也可以是独立的 .html 文件。这取决于你。

所有这些都可以通过普通的旧 CGI 实现。您不需要为此使用任何 Web 框架。但是随着您的应用程序的发展,您会发现现代框架让您的生活更轻松。


使用http://asciiflow.com/创建的图表

【讨论】:

  • 感谢详细的解释,值得深思。
【解决方案2】:

您可以在 CGI 脚本中使用 use Module_Name;require Module_Name; 导入模块。 http://perldoc.perl.org/functions/use.html http://perldoc.perl.org/functions/require.html

Plack Web 框架不是灵丹妙药,CGI 并没有死,FCGI 是所有速度的所在。

不要相信 Plack 的炒作。首先了解它是什么!

【讨论】:

  • 您是否有任何资料证明 FCGI 拥有所有速度?我很想看看他们。根据我的专业经验,精心设计和正确配置的 Plack 应用程序在速度和灵活性方面都胜过 FCGI 实现。不幸的是,我无法发布我们为此在 $work 上运行的内部基准。但是,无论如何,这不是问题所在。
  • 实际上,在我看来,perlmonks 线程的内容与您所说的完全不同。
猜你喜欢
  • 2012-03-10
  • 1970-01-01
  • 2012-01-19
  • 2015-05-27
  • 2012-10-15
  • 2015-04-03
  • 2013-03-11
相关资源
最近更新 更多