简体   繁体   English

多个CGI Perl脚本

[英]Multiple CGI Perl scripts

This is kind of a theoretical question. 这是一个理论问题。 I'm trying to develop a Perl application based on the producer-consumer paradigm. 我正在尝试基于生产者 - 消费者范例开发Perl应用程序。 One of the scripts creates a file with data, while the other reads the data and has to present it in a HTML. 其中一个脚本创建一个包含数据的文件,而另一个脚本读取数据并且必须在HTML中显示。 There's also a third file, a HTML form, that starts the producer perl file. 还有第三个文件,一个HTML表单,它启动生产者perl文件。

What I don't know is how to run both the producer and the consumer at the same time using CGI, and I couldn't find information about it online (at least not how I searched for it). 我不知道是怎么跑兼顾生产者和使用CGI同时消费者,我不能在网上找到关于它的信息(至少不是我怎么寻找它)。

I would like to know if you could tell me where to find this kind of information so I could test the app in the Apache server. 我想知道你是否可以告诉我在哪里可以找到这种信息,以便我可以在Apache服务器上测试应用程序。

Thanks in advance 提前致谢

You can import modules with use Module_Name; 您可以use Module_Name;导入模块use Module_Name; or require Module_Name; 或者require Module_Name; in your CGI script. 在你的CGI脚本中。 http://perldoc.perl.org/functions/use.html http://perldoc.perl.org/functions/require.html http://perldoc.perl.org/functions/use.html http://perldoc.perl.org/functions/require.html

A Plack web framework is not a silver bullet, CGI is not dead and FCGI is where all the speed is at. Plack网络框架不是银弹,CGI没有死,FCGI是所有速度所在的地方。

Do not buy into the Plack hype. 不要买入普拉克炒作。 Learn what it is first! 了解它的第一个!

Disclaimer: I think what this question boils down to is how to have two different components of a program interact with each other to create one application that is accessible from the web. 免责声明:我认为这个问题归结为如何让程序的两个不同组件相互交互,以创建一个可从Web访问的应用程序。 If that is not what you want, just treat this as food for thought. 如果那不是你想要的,那就把它作为思考的食物吧。

Common Gateway Interface 通用网关接口

You are talking about CGI scripts in your question. 您在谈论您的问题中的CGI脚本。 (Emphasis mine). (强调我的)。

I'm trying to develop a Perl application based on the producer-consumer paradigm. 我正在尝试基于生产者 - 消费者范例开发Perl 应用程序 One of the scripts creates a file with data, while the other reads the data and has to present it in a HTML. 其中一个脚本创建一个包含数据的文件,而另一个脚本读取数据并且必须在HTML中显示。

In general, CGI works in a way that a request goes through a web server, and is passed on to an application. 通常, CGI以请求通过Web服务器的方式工作,并传递给应用程序。 That application might be written in Perl. 该应用程序可能是用Perl编写的。 If it is a Perl script, then that script is run by the perl interpreter. 如果它是Perl脚本,则该脚本由perl解释器运行。 The web server starts that process. Web服务器启动该过程。 It can access the request information through the CGI, which is mostly environment variables. 它可以通过CGI访问请求信息,CGI主要是环境变量。 When the process is done, it writes data to STDOUT, which the web server takes as a response and sends back. 完成此过程后,它会将数据写入STDOUT,Web服务器将其作为响应并发回。

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

Now because there is only one process involved behind the web server, you cannot have two scripts. 现在因为Web服务器后面只涉及一个进程,所以不能有两个脚本。 There is just no way for the server to communicate with two things at the same time. 服务器无法同时与两件事进行通信。 That's not how CGI works. 这不是CGI的工作方式。

A combined approach 综合方法

Instead, you need to wrap your two scripts into a single point of entry and turn them into some kind of components. 相反,您需要将两个脚本包装到单个入口点并将它们转换为某种组件。 Then you can have them talk to each other internally, while on the outside the web server is only waiting for one program to finish. 然后你可以让他们在内部互相交谈,而在外面,Web服务器只等待一个程序完成。

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

To translate this into Perl, let's first determine some terminology. 要将其转换为Perl,我们首先确定一些术语。

  • script : a Perl program that is in a .pl file and that does not have its own package script :一个.l文件中的Perl程序,它没有自己的package
  • module : a Perl module that is in a .pm file and that has a package with a namespace that fits to the file name module :一个位于.pm文件中的Perl模块,它具有一个package适合文件名的命名空间的package

Let's assume you have these two Perl scripts that we call producer.pl and consumer.pl . 假设您有两个我们称之为producer.plconsumer.pl的 Perl脚本。 They are heavily simplified and do not take any arguments into account. 它们大大简化,不考虑任何参数。

producer.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 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;

This is as simplified as it gets. 这是简化得到的。 There is one script that creates data and one that consumes it. 有一个脚本可以创建数据,另一个脚本可以使用它。 Now we need to make these two interact without actually running them. 现在我们需要在不实际运行它们的情况下进行这两个交互。

Let's jump ahead and assume that we have already refactored both of these scripts and turned them into modules. 让我们继续前进并假设我们已经重构了这两个脚本并将它们转换为模块。 We'll see how that works a bit later. 我们稍后会看到它是如何工作的。 We can now use those modules in our new foo.pl script. 我们现在可以在新的foo.pl脚本中使用这些模块。 It will process the request, ask the producer for the data and let the consumer turn the data into the format the reader wants. 它将处理请求,向生产者询问数据并让消费者将数据转换为读者想要的格式。

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;

This is very straightforward. 这非常简单。 We read the parameter from the CGI, pass them to the producer, and pass the product to the consumer. 我们从CGI读取参数,将它们传递给生产者,并将产品传递给消费者。 That gives us output, which we print out so it goes back to the server, which sends a response. 这给了我们输出,我们打印输出,然后返回服务器,发送响应。

Let's take a look at how we turned the two scripts into simple modules. 我们来看看如何将两个脚本转换为简单的模块。 Those do not need to be object oriented, though that might be preferred. 那些不需要面向对象,尽管这可能是首选。 Note that the spelling of the file names is now different. 请注意,文件名的拼写现在是不同的。 Module names conventionally start with capital letters. 模块名称通常以大写字母开头。

Producer.pm Producer.pm

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

sub produce {
    my @args = @_;

    return "lots of data\n";
}

1;

Consumer.pm Consumer.pm

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

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

    return $data; # this is really simple
}

1;

Now we have two modules that do the same as the scripts if you call the right function. 现在,如果调用正确的函数,我们有两个与脚本相同的模块。 All I did was put a namespace ( package ) at the top and wrap the code in a sub . 我所做的就是在顶部放置一个命名空间( package ),并将代码包装在一个sub I also removed the CGI part. 我也删除了CGI部分。

In our example, it's not necessary for the producer to write to a file. 在我们的示例中,生产者没有必要写入文件。 It can just return the data structure. 它只能返回数据结构。 The consumer in turn doesn't need to read from a file. 消费者反过来不需要从文件中读取。 It just takes a variable with the data structure and does stuff to it to present it. 它只需要一个带有数据结构的变量,并为它提供东西来呈现它。

If you stick to consistent function names (like produce and consume , just better), you can even write multiple producers or consumers. 如果你坚持使用一致的函数名称(比如produceconsume ,就更好),你甚至可以编写多个生产者或消费者。 We have basically defined an interface here. 我们在这里基本上定义了一个接口。 That gives us the possibility to refactor the internals of the code without breaking compatibility, but also to stick in completely different producers or consumers. 这使我们有可能在不破坏兼容性的情况下重构代码的内部,但也可以坚持完全不同的生产者或消费者。 You can switch from the one-line-string producer to one that looks up stuff in a database in a heartbeat, as long as you stick to your interface. 只要您坚持使用界面,就可以从单行字符串生成器切换到在心跳中查找数据库中的内容的生成器。

Essentially, what we just did can also be shown like this: 基本上,我们刚刚做的也可以这样显示:

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

This might look slightly familiar. 这可能看起来有点熟悉。 It is essentially the Model-View-Controller (MVC) pattern. 它本质上是模型 - 视图 - 控制器 (MVC)模式。 In a web context, the model and the view often only talk to each other through the controller, but it's pretty much the same. 在Web环境中,模型和视图通常只通过控制器相互通信,但它几乎相同。

Our producer is a data model . 我们的制作人是一个数据模型 The consumer turns the data into a website that the user can see, so it's the view . 消费者将数据转换为用户可以看到的网站,因此它就是视图 The main program inside foo.pl that glues both of them together controls the flow of data. foo.pl中的主程序将两者粘合在一起控制着数据流。 It's the controller . 这是控制器

The initial website that triggers the whole thing could be either part of the program, and be shown if no parameters are passed, or could be a stand-alone .html file. 触发整个事物的初始网站可以是程序的一部分,如果没有传递参数则显示,或者可以是独立的.html文件。 That's up to you. 随你(由你决定。

All of this is possible with plain old CGI. 所有这一切都可以用普通的旧CGI实现。 You don't need to use any web frameworks for it. 您不需要使用任何Web框架。 But as you grow your application, you'll see that a modern framework makes your life easier. 但随着您的应用程序的发展,您将看到现代化的框架使您的生活更轻松。


The diagrams where created with http://asciiflow.com/ 使用http://asciiflow.com/创建的图表

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM