Perl Web 服务器初级编程

类别:网站制作 点击:0 评论:0 推荐:

             如果你对WEB服务器编程和LINUX环境下PERL CGI编程感兴趣,建议你阅读下面内容,即使没有CGI开发经验,只要了解perl语言,就不会感觉困难。由于我第1次写作Blog文章,如有错误请指出,谢谢。
  
              HTTP消息分为2种,客户机发送给服务器的HTTP请求以及服务器回送给客户机的HTTP响应.
 
              这2者都由 一个必不可少的头(由一些要求的和许多可选的头行组成)  +  一个可选的主体(要传输的文档) 构成.以下是获取头和主体的各种方法。

              GET:从服务器获取头和主体
                          GET /index.html.HTTP/1.1
                          Host:www.myserver.com
              HEAD:只获得资源头
                         HEAD /index.html.HTTP/1.1
                          Host:www.myserver.com
              PUT:在HTTP主体中发送信息给服务器
                        PUT /doc/newdoc.html HTTP/1.1
                        Host:www.myserver.com
                       Content-length:2043
                       <html>
                       ...........................
              POST:在HTTP主体中发送信息给服务器
                         POST /index.html.HTTP/1.1
                          Host:www.myserver.com
                         Content-Length:23
                         Roses=red&violets=blue
              TRACE:跟踪一个HTTP请求---响应交换,不是一个用于正常请求的方法
                         TRACE * HTTP/1.1
                         Host:www.myserver.com
              DELETE:出于安全考虑,一般服务器不支持此方法
                         DELETE:/doc/olddoc.html HTTP/1.1
                         host:www.myserver.com

              POST用于发送CGI脚本这样的服务器应用程序将处理,以创建资源(例如在服务器上的进程,为每个用户创建进程也成为人们指责CGI的重要原因)的内容,URL指明了数据发送的应用程序,比如如果表单数据超过了256个字符,将不能用GET方法,而只能使用POST。
              PUT指示正在创建一个由URL描述的新资源。URL描述了新资源,并且可以同随后的GET请求一起来检索它。

             HTTP响应: HTTP状态行(HTTP协议,响应码)   +  描述响应类型的3位数  + 响应的文本描述
                                Eg: HTTP/1.1 200 OK
                                Eg: HTTP/1.1 404 NOT FOUND
            
             HTTP头:任意,客户与服务器使用头相互通信  (#头第1字母大写,:后需有空格)
                                GET /~unixdb/test.html   HTTP1.1                      #状态行
                                Connection: Keep-Alive
                                User-Agent: Mozilla/4.75 [en] (X11;u;Linux 2.2.17 i686)
                                Host: www.myserver.com
                                Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, text/html, */*
                                Accept-Encoding: gzip
                                Accept-Language: en
                                Accept-Charset: iso-8859-1,*,utf-8

             这样,一个典型的GET请求的服务器响应:
                                HTTP1/1 200 OK                     #HTTP status
                                Date: Tue,7 Sep 2004 23:35 GMT           #HTTP Header
                                Server: Apache /1.3.12(Unix) mod_ssl/2.6.4 OpenSSL/0.9.5a
                                Connection:  close
                                Content-Type:  text/html
                                <Title>testing</Title>
                                testing
 
              HTTP主体:PUT和POST方法需要主体,非可选。在Perl中,主体与头使用\n\n(正式分割符序列是\012\015\012\015) 分开
              Eg:             
                                 my $request=<>;
                                 my (@headers,$body);
                                 while(<>)
                                 {
                                       push @headers,$_    if  1../^$/;
                                       $body.=$_      if /^$/..eof;              #means  $body=$body . $_;
                                  }

                对照:CGI响应是没有状态行的HTTP响应,被要求发送的头有一个是Content-Type头,后面跟着一个介质类型,以定义主体内容。
                   Eg1: print “Content-Type: text/plain\n\n“;
                   Eg2: print “Content-Type: image/jpeg\n\n”;            
                   
                   CGI环境变量我们可以参考
                     my $docroot=$ENV {'DOCUMENT_ROOT'};
                  例如我们可以这样查看我们的环境变量:
                    #!/usr/bin/perl -w
                   #author:nick
                   #goal:check the ENV
                   #env.cgi
                   use strict;
                   print "content-type: text/html \n\n";
                   print "<html><title>Enviroment Variables</title><head>\n";
                   print "Here is your Enviroment Variables</head>\n" ;
                   print "<body><blockquote><table border=1>\n";
                  foreach (sort keys %ENV)
                  {
                      print "\t<tr><td> $_ </td><td>$ENV{$_} </td></tr>\n";
                   }
                    print "</table></blockquote></body></html>\n";
#run the program
#you can see:
#CONTENT-LENGTH: the length of HTTP requirement,here it should display 0,for we
#did not put or post mainbody here
#GATEWAY-INTERFACE: cgi protocol and version
#HTTP-REFERER: URI of resource
#HTTP_USER_AGENT: client's software,maybe IE or Netscape
#PATH: client's additional path
#QUERY_STRING: requesting URI's query-string, maybe null or important for CGI
#programs
#REMOTE_ADDR: client's IP
#REMOTE_HOST: client's host name
#REQUEST_METHOD : the HTTP method of request,maybe "get" or "post"
#SCRIPT_FILENAME: script's File Path
#SCRIPT_NAME: script's URL
#SERVER_NAME :server's host name
#SERVER_SOFTWARE: web server listening request

               Perl 创建HTTP头和HTML头的过程:
               面向对象:    print $cgi->header  (print $cgi->header('image/jpeg'))    print $cgi->start_html(“my cgipage“);
               面向过程:    print header;(print header('image/jpeg'))    print start_html(“my cgipage“);

               高级头:
                   print $cgi->header(-status=>'200 Nistal',
                                                 -type=>'text/html',       
                                                 -expires=>'+30s',
                                                 -nph=>1,
                                               );
                 产生的头如下:
                          HTTP/1.0 200 Nistal
                          Status:200 Nistal
                          Expires:Mon 25 Dec 2005 4:35 GMT
                          Date:Mon 25 Dec 2005 4:15 GMT
                          Content-Type: text/html; charset=ISO-8859-1
                参数列表:
                          -status  响应代码和消息
                          -expires截止时间或日期  
                          -nph     切换到非解析头模式  脚本输出产生时被直接发送给客户机,服务器不干预
                                      为了使输出非缓冲,我们可以设置$|=1来激活autoflush模式;也可以把nph作为导入标记来传递激活nph模式
                                 use CGI qw(:standard'nph');
                        
                高级Document头:
                            #! /usr/bin/perl 
                            #headertag.cgi
                            use warnings;
                            use strict;
                            #import invented 'link' and 'myheadertag' elements
                            use CGI qw(:standard link myheadertag);
                           
                            print header;
                            print start_html(
                                    -title=>'Big Document Header',
                                    -author=>'[email protected]',
                                    -xbase=>'http://www.myserver.com',       #文档的基本URL
                                    -target=>'my_panel',         #文档目标桢
                                    -meta=>{                         #指向元标记的名字/值对的一个哈希引用
                                                   description=>'How to define a CGI header with Metatags',
                                                    keywords=>'meta,metadata,cgi,tags,html,perl',
                                                 },
                                     -style=>{
                                                 src=>'/css/mystylesheet.css'
                                                   },
                                                   };
                CGI模块自动为我们处理URL大部分转义和非转义字符
                 print “<a href=“,$cgi->escape($unescaped_url).'?'.$cgi->escape($key).'='.$cgi->escape($value),“>Link</a>“;
                URL方法仅仅返回脚本的URL
                $cgi->url(-full=>1)  # http://myserver/path/script/nistal
                $cgi->url(-absolute=>1) #absolute path /home/sites/cgi/script/nistal
                $cgi->url(-relative=>1)  #relative URL /cgi/script/nistal
            
                保存和加载CGI状态
                 保存:  if(open(STATE , “> $state“))
                            {
                                   $cgi->save(STATE);
                                   close STATE;
                             }
                  加载: if(open(STATE,$state))
                            {
                                    $cgi->new CGI(STATE);
                                    close STATE;
                             }
                
               以下是简单的CGI脚本:
               1.一个简单的Web服务器,为由$docroot声明的跟目录外的页面服务。它仅仅处理GET请求,并且如果他们同声明的URL相匹配的话将文档回送给客户机
                   #! /usr/local/perl -w
                   #httpd.pl
                  use warnings;
                  use HTTP::Daemon;
                  use HTTP::Status;              #for RC_FORBIDDEN

                  my $docroot= “/home/httpd/html“;
                  my $httpd= new HTTP::Daemon;

                  print “Server running at :“,$httpd->url(),“\n“;
                  while(my $connection=$httpd->accept)
                  {
                         while(my $request=$connection->get_request)
                         {
                                 if($request->method eq 'GET')
                                  {
                                      my $file=$request->url->path;
                                      $connection->send_file_response(“/$docroot/$file“);
                                  }
                                 else{
                                       $connection->send_error(RC_FORBIDDEN);
                                       }
                                   $connection->close;
                         }
                          undef($connection);
                  }
                 HTTP::Daemon对象从IO::Socket::INET模块继承,我们可以在其上进行SOCKET操作。daemon对象扫描本地主机以获取一个可能的名字,并选择一个端口号服务 Eg:在Unix服务器上
                 Server running at: http://localhost.localdomain:1640/
                 通过浏览器指向服务器发送简单请求后,创建Daemon对象,并由其接收呼叫,等待连接,当客户机连接后,返回一个连接对象。检索将GET请求翻译成一个路径的URI,最后我们在连接对象上调用send_file_response将请求文档回送客户机,if not found,发送404 Not Found响应,if 是目录,发送501 Not Implemented错误。

                 列举HTTPD::Daemon的方法:
                        1.new  创建新服务器
                           Eg: $httpd=new HTTPD:: Daemon(
                                                                                 LocalAddr=>'www.myserver.com',
                                                                                 Localport=>80,
                                                                                 );
                        2.$httpd->accept  接受来自客户机连接请求,返回HTTP::Daemon::ClientCoon对象
                        3.$httpd->url  由后台程序处理的主机和端口名     http://server:port/
                       4.$conn->get_request 读取来自客户机的HTTP请求并返回一个HTTP::request对象。能接受块传输和使用multipart/form-data编码的文档上载。一旦头 被读取就让get_request返回,然后就可以使用read_buffer来成块读数据。
                        5.$conn->read_buffer
                        6.$conn->reason  将get_request失败的原因返回
                        7.$conn->send_status_line 发送一个HTTP响应状态行给客户机
                                            Eg1:  $conn->send_status_line(RC_NOT_FOUND);
                                                   #generate standard '404' response
                                            Eg2:  $conn->send_status_line(404,“It wasn't there!“);
                                                   #Eg2 has the same effect as Eg1 has
                        8.$conn->send_file_response 试图打开,读和发送文档内容给客户机
                        9.$conn->send_file 试图发送传递的文档句柄内容给客户机

                       
                          2.一个简单的服务器推计数器  
                                   服务器推:不断的用新的信息来更新客户机
                              #! /usr/bin/perl -w
                              #nph-push.cgi 
                              #use strict            
                              use CGI::Push qw(:standard);

                              my $cgi=new CGI::Push ;
                              $cgi->do_push(-next_page=> \$refresh);
                              
                              sub refresh{
                                                my ($cgi,$count) = @_;     #passed in by CGI::Push
                                                my $page=start_html(“CGI PUSH DEMO“)
                                                                 .p(“The count is $count“)
                                                                 .end_html;
                                                returen $page;
                       }
                       CGI::PUSH应用程序使用do_push方法注册一个子程序,调用该子程序以在每一次循环产生页面内容。CGI::PUSH跟踪记数并传递给子程序
                        如果do-push 注册的子程序回送一个未定义值作为其结果来选择结束更新和终止HTTP响应。
                          #! /usr/bin/perl -w
                          #nph-pushlast.cgi
                          use warnings;
                          use strict;

                          use CGI::Push;
                          my $cgi=new CGI::Push;
                         $cgi->do_push(-next_page=> \$refresh,-last_page=>\$done );

                         sub refresh{
                                           my ($cgi,$count)=@_;       #passed in by CGI::Push
                                           return  undef if $count==10;
                                          return  $cgi->start_html,$cgi->p(“The count is $count“),$cgi->end_html;
                                         }
                         sub done{
                                          my ($cgi,$count)=@_;
                                          return $cgi->start_html,“Count stopped on $count“,$cgi->end_html;
                                       }
                        模块在内部把这个列表发送给print,所以print将接受的任何东西是-next_page或-last_page子程序的一个正确返回值



             

本文地址:http://com.8s8s.com/it/it30844.htm