博客专区 > 史帝文的博客 > 博客详情
使用Hprose制作一个简单的分布式应用程序
史帝文 发表于7个月前
使用Hprose制作一个简单的分布式应用程序
  • 发表于 7个月前
  • 阅读 135
  • 收藏 1
  • 点赞 0
  • 评论 0

IBM Bluemix免费试用!>>>   

使用Hprose制作一个简单的分布式应用程序只需要几分钟的时间。本文将用一个简单的实例来带您快速浏览使用Hprose for PHP进行分布式程序开发的全过程。

一、安装Hprose for PHP

 

安装条件

1)PHP 5.0或更高版本

2)Apache、IIS、lighttpd、nginx或其它任何一款可以运行php的web服务器。

3)Hprose for PHP支持SAE云计算平台,在SAE云计算平台上不需要单独的服务器。

 

安装方法

1)直接将Hprose for PHP的所有文件(hproseCommon.php,hproseIO.php,hproseHttpServer.php和hproseHttpClient.php)直接复制到您的开发环境的目录下即可,无需任何安装步骤。

2)Hprose for PHP有三个版本,分别是面向普通的PHP配置,带有curl扩展的PHP配置和SAE平台的。这三个版本目前只有hproseHttpClient.php是有区别的,但是用法完全相同。

 

二、创建Hprose的Hello服务器

 

      创建PHP的Hprose的服务器非常简单。下面我们以Linux环境为例来讲解。假设在Linux下已经配置好了Web服务器(apache、lighttpd或其它任何http服务器),并且可以执行PHP程序,发布路径为/var/www。然后我们在发布目录下建立一个hprose目录,把Hprose for PHP的几个文件放到该目录下。然后在发布目录下创建一个helloserver.php文件,内容如下:

<?php include("hprose/hproseHttpServer.php"); function hello($name){ return "Hello".$name; } $server = new HproseHttpServer(); $server->addFunction("hello"); //发布函数 $server->handle(); ?>

测试:访问http://localhost/helloserver.php,如果出现“Fa1{s5"hello"}z”就表示服务发布成功。

猜测这个序列化结果的含义:

F表示function;a表示List/Array;1表示List/Array的长度;{和}是分隔符,便于解析;s表示String;4表示后接string的长度;z表示end。

三、创建Hprose的Hello客户端

 

PHP的Hprose客户端创建更加容易,同样在发布目录下创建helloclient.php文件,内容如下:

<?php include("hprose/hproseHttpClient.php"); $client = new HproseHttpClient("http://localhost/helloserver.php"); echo $client->Hello("Hprose"); ?>

测试:访问http://localhost/helloclient.php,或者在命令行上输入php helloclient.php,如果出现“Hello Hprose”就表示客户端创建成功。

四、个人总结

       Hprose的应用就三件事,第一,复制Hprose文件进项目;第二,写Hprose服务端;第三,写Hprose客户端。

Hprose服务端要做的事就两件。一、new一个HproseHttpServer对象;二、用这个对象发布服务,包括函数、方法、对象甚至类。

Hprose客户端要做的事就两件。一、new一个HproseHttpClient对象;二、用这个对象调用服务端发布的各种服务。

注意:

1、server和client之间用序列化结果交互,在server中使用echo、var_dump等函数会扰乱序列化结果,故不能使用,在client中可以使用。

疑问:

1、当Hprose服务端或客户端有错时,服务器会报500错误,但是不好调试。如何调试。

 

 

 

Hprose for php(二)——服务器

 

本文将介绍Hprose for php服务器的更多细节

 

1、发布服务

Hprose提供多种方法发布服务,除了提供跟PHPRPC中相同的add方法以外,还提供了更多方便的方法。

写完服务器后访问之,如果会出现类似“Fa1{s5"hello"}z的字符串就说明服务器没问题。

a)发布函数

大部分函数可以作为Hprose服务发布,甚至包括PHP中的内置的函数。但如果参数或结果中包含有资源类型(比如mysql_connect,mysql_query等),那么这种函数就不能够发布。(也就是说如果Hprose无法传递的数据类型的函数就不行,个人猜测)

你可以同时发布多个函数,不论是你自定义的,还是PHP内置的都可以。把函数名放到数组中用addFunctions一次添加多个。

<?php include("hprose/hproseHttpServer.php"); $server = new HproseHttpServer(); $server->addFunction("trim"); $server->addFunctions(array('md5', 'sha1')); $server->handle(); ?>

 

b)发布方法

Hprosefor PHP 也支持发布类的静态方法和对象的实例方法。

注意:php中方法与函数的区别:方法指的是类中的函数。

<?php include("hprose/hproseHttpServer.php"); class Example1 { static function foo() { return 'foo'; } function bar() { return 'bar'; } } $server = new HproseHttpServer(); $server->addMethod('foo', 'Example1'); $server->addMethod('bar', new Example1()); $server->handle(); ?>

这里foo是一个静态方法,所以添加时第二个参数是类名。而bar是一个实例方法,所以添加时是一个Example1的实例对象。

 

c)别名机制

当在服务器中同时发布两个不同类中的同名方法时,是否会有冲突?

答案是会,后添加的方法会将前面添加的方法覆盖掉。于是Hprose提供了一种别名机制。

<?php include("hprose/hproseHttpServer.php"); function hello($name) { return 'Hello ' . $name; } class Example1 { static function foo() { return 'foo'; } function bar() { return 'bar'; } } class Example2 { function foo() { return 'foo, too'; } function bar() { return 'bar, too'; } } $server = new HproseHttpServer(); $server->addFunction('hello', 'hi'); $server->addMethod('foo', 'Example1', 'ex1_foo'); $server->addMethod('bar', new Example1(), 'ex1_bar'); $server->addMethods(array('foo', 'bar'), new Example2(), array('ex2_foo', 'ex2_bar')); $server->handle(); ?>

从上面这个例子,我们就会发现不论是函数还是方法都可以通过别名来发布,只需要在最后再加一个别名参数就可以了。同时添加多个方法(或函数)时,别名也应该是多个,并且个数要跟方法(或函数)名个数相同,且一一对应。

最后要注意的一点是,通过别名发布的方法(或函数)在调用时如果用原方法(或函数)名调用是调用不到的,也就是说只能用别名来调用。

 

d)发布对象

除了向上面通过addMethod和addMethods发布方法以外,Hprose可以让您更方便的发布一个对象上的方法,那就是使用addInstanceMethods,addInstanceMethods用来发布指定对象上的指定类层次上声明的所有public实例方法。它有三个参数,其中后两个是可选参数。如果您在使用addInstanceMethods方法时,不指定类层次(或者指定为NULL),则发布这个对象所在类上声明的所有public实例方法。这个方法也支持指定名称空间(别名前缀)。

<?php include("hprose/hproseHttpServer.php"); class Example2 { function foo() { return 'foo, too'; } function bar() { return 'bar, too'; } } $server = new HproseHttpServer(); $server->addInstanceMethods(new Example2(), NULL, 'ex2'); $server->handle(); ?>

效果是跟上面别名机制例子中发布ex2_foo和ex2_bar方法一样的。

 

e)发布类

跟addInstanceMethods方法类似,使用addClassMethods可以让您更方便的发布一个类上的方法。它有三个参数,其中后两个是可选参数。第一个参数是方法的发布类,第二个参数为方法的执行类,第三个参数为名称空间(别名前缀)。

 

f)迷失的方法

当客户端调用一个服务器端没有发布的方法时,默认情况下,服务器端会抛出错误。但是如果你希望能对客户端调用的不存在的方法在服务器端做特殊处理的话,你可以通过addMissingFunction方法来实现。

这是一个很有意思的方法,它用来发布一个特定的方法,当客户端调用的方法在服务器发布的方法中没有查找到时,将调用这个特定的方法。

使用addMissingFunction发布的方法可以是实例方法、静态方法或者函数,但是只能发布一个。如果多次调用addMissingFunction方法,将只有最后一次发布的有效。

用addMissingFunction发布的方法参数应该为两个:

第一个参数表示客户端调用时指定的方法名,方法名在传入该方法时全部是小写的。

第二个参数表示客户端调用时传入的参数列表。例如客户端如果传入两个参数,则 args 的列表长度为2,客户端的第一个参数为 args 的第一个元素,第二个参数为 args 的第二个元素。如果客户端调用的方法没有参数,则 args为长度为0 的列表。

除了可直接使用addMissingFunction来处理迷失的方法以外,你还可以通过addFunction或addMethod发布一个别名为星号(*)的方法。效果是一样的。

 

2、服务器开关

 

a)隐藏发布列表

发布列表的作用相当于Web Service的WSDL,与WSDL不同的是,Hprose的发布列表仅包含方法名,而不包含方法参数列表,返回结果类型,调用接口描述,数据类型描述等信息。

如果您不希望用户直接通过浏览器就可以查看发布列表的话,您可以禁止服务器接收GET请求。方法很简单,只需要在调用handle方法之前调用setGetEnabled方法,将参数设置为false即可。

$server->setGetEnabled=false;

 

b)调试开关

$server->setDebugEnabled=true; //打开调试

 

c)P3P开关

在Hprose的http服务中还有一个P3P开关,这个开关决定是否发送P3P的http头,这个头的作用是让IE允许跨域接收的Cookie。当您的服务需要在浏览器中被跨域调用,并且希望传递Cookie时(例如通过Cookie来传递Session ID),您可以考虑将这个开关打开。否则,无需开启此开关。此开关默认是关闭状态。开启方法与上面的开关类似,只需要在调用handle方法之前调用setP3PEnabled方法,将参数设置为true即可。

 

d)跨越开关

Hprose 支持 JavaScript、ActionScript 和 SilverLight 客户端的跨域调用,对于 JavaScript 客户端来说,服务器提供了两种跨域方案,一种是 W3C标准跨域方案,这个只需要在服务器端调用handle方法之前调用setCrossDomainEnabled方法,将参数设置为true即可。当你在使用Hprose专业版提供的服务测试工具Nepenthes(忘忧草)时,一定要注意必须要打开此开关才能正确进行调试,否则Nepenthes将报告错误的服务器。

另一种跨域方案同时适用于以上三种客户端,那就是通过设置跨域策略文件的方式。这个只需要将crossdomain.xml放在服务器发布的根目录上即可。

对于SilverLight客户端来说,还支持clientaccesspolicy.xml 这个客户端访问策略文件,它的设置方法跟crossdomain.xml是一样的,都是放在服务器发布的根目录上。

关于crossdomain.xml 和clientaccesspolicy.xml 的更多内容请参阅:

http://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html

http://www.adobe.com/devnet/flashplayer/articles/fplayer9_security.html

http://msdn.microsoft.com/en-us/library/cc197955%28v=VS.95%29.aspx

http://msdn.microsoft.com/en-us/library/cc838250%28v=VS.95%29.aspx

 

3、服务器事件

 

也许您可能还希望设置其它的http头,或者希望在发生错误时,能够在服务器端进行日志记录。甚至希望在调用发生的前后可以做一些权限检查或日志记录等。在Hprose中,这些都可以轻松做到。Hprose提供了这样的事件机制。

Hprose服务器提供了四个事件,它们分别是onBeforeInvoke、onAfterInvoke、onSendHeader和onSendError。下面我们就来对这四个事件分别做一下介绍。

 

a)onBeforeInvoke事件

当服务器端发布的方法被调用前,onBeforeInvoke事件被触发,它有三个参数,他们从左到右的顺序分别是name,args和byRef。其中name为客户端所调用的方法名,args为方法的参数,byRef表示是否是引用参数传递的调用。

您可以在该事件中做用户身份验证,例如IP验证。也可以作日志记录。如果在该事件中想终止调用,抛出异常即可。

 

b)onAfterInvoke事件

当服务器端发布的方法被成功调用后,onAfterInvoke事件被触发,其中前三个参数与onBeforeInvoke事件一致,最后一个参数result表示调用结果。

当调用发生错误时,onAfterInvoke事件将不会被触发。如果在该事件中抛出异常,则调用结果不会被返回,客户端将收到此事件抛出的异常。

 

c)onSendHeader事件

当服务器返回响应头部时,onSendHeader事件会被触发,该事件无参数。

在该事件中,您可以发送您自己的头信息,例如设置Cookie。该事件中不应抛出任何异常。

 

d)onSendError事件

当服务器端调用发生错误,或者在onBeforeInvoke、onAfterInvoke事件中抛出异常时,该事件被触发,该事件只有一个参数error。

您可以在该事件中作日志记录,但该事件中不应再抛出任何异常。

 

 

Hprose for php(三)——客户端

 

1、直接通过远程方法名进行远程调用

在快速入门一章中,我们已经见识过这种方式的调用了,这里再来具一个例子来进行说明:

<?php include("hprose/hproseHttpClient.php"); $client = new HproseHttpClient("http://www.hprose.com/example/"); echo "<pre>"; echo $client->sum(1, 2, 3, 4, 5); echo "\r\n"; echo $client->Sum(6.0, 7.0, 8.0); echo "\r\n"; $userList = $client->getUserList(); print_r($userList); echo "</pre>"; ?>

 

从这个例子中,我们可以看出通过远程方法名进行调用时,远程方法名是不区分大小写的,所以不论是写sum还是Sum都可以正确调用,如果远程方法返回结果中包含有某个类的对象,而该类并没有在客户端明确定义的话,Hprose会自动帮你生成这个类的定义(例如上例中的User类),并返回这个类的对象。

 

2、通过Invoke方法进行远程调用

 

非引用参数传递

<?php include("hprose/hproseHttpClient.php"); $client = new HproseHttpClient("http://www.hprose.com/example/"); echo "<pre>"; $args = array(1, 2, 3, 4, 5); echo $client->invoke("sum", $args); echo "\r\n"; $args = array(6.0, 7.0, 8.0); echo $client->invoke("Sum", $args); echo "\r\n"; $userList = $client->invoke("getUserList"); print_r($userList); echo "</pre>"; ?>

运行结果与上面例子的运行结果完全相同。但是我们发现用invoke方法并不方便,因为当有参数时,必须要把参数单独放入一个变量中才可以进行传递。所以通常我们无需直接使用invoke方法,除非我们需要动态调用。另外,还有一种情况下,你会用到invoke方法,那就是在进行引用参数传递时。

 

引用参数传递

下面这个例子很好的说明了如何进行引用参数传递:

<?php include("hprose/hproseHttpClient.php"); $client = newHproseHttpClient("http://www.hprose.com/example/"); echo"<pre>"; $args =array(array("Mon"=>1,"Tue"=>2,"Wed"=>3,"Thu"=>4,"Fri"=>5,"Sat"=>6,"Sun"=>7)); echo"args(before invoke):\r\n"; print_r($args); $result =$client->invoke("swapKeyAndValue", $args, true); echo"args(after invoke):\r\n"; print_r($args); echo"result:\r\n"; print_r($result); echo"</pre>"; ?>

我们看到运行前后,$args中的值已经改变了。

这里有一点要注意,当参数本身是数组时,该数组应该作为参数数组的第一个元素传递,否则程序将会出错,或者在调用中陷入等待状态,这样的错误不容易被找到,因此一定要注意这一点。

 

 

3、异常处理

Hprose for PHP的客户端只支持同步调用,因此在调用过程中,如果服务器端发生错误,异常将在客户端被直接抛出,使用try...catch语句块即可捕获异常,通常服务器端调用返回的异常是HproseException类型。但是在调用过程中也可能抛出其它类型的异常。

例如,当调用不存在的方法时:

<?php include("hprose/hproseHttpClient.php"); $client = new HproseHttpClient("http://www.hprose.com/example/"); echo "<pre>"; try { echo $client->unexistMethod(); } catch (Exception $e) { print_r($e); } echo "</pre>"; ?>

 

 

4、超时设置

Hprose 1.2 for PHP及其之后的版本中增加了超时设置。只需要设置客户端对象上的setTimeout属性即可,单位为毫秒。当调用超过timeout的时间后,调用将被中止。

 

 

5、HTTP参数设置

目前的版本只提供了http客户端实现,针对于http客户端,有一些特别的设置,例如代理服务器、http标头等设置,下面我们来分别介绍。

 

代理服务器

默认情况下,代理服务器是被禁用的。可以通过setProxy来设置http代理服务器的地址和端口。参数是字符串,例如:"tcp://10.54.1.39:8000",默认值为NULL。

 

HTTP标头

有时候您可能需要设置特殊的http标头,例如当您的服务器需要Basic认证的时候,您就需要提供一个Authorization标头。设置标头很简单,只需要调用setHeader方法就可以啦,该方法的第一个参数为标头名,第二个参数为标头值,这两个参数都是字符串型。如果将第二个参数设置为NULL,则表示删除这个标头。

标头名不可以为以下值:Context-Type、Context-Length、Host。

因为这些标头有特别意义,客户端会自动设定这些值。

另外,Cookie这个标头不要轻易去设置它,因为设置它会影响Cookie的自动处理,如果您的通讯中用到了Session,通过setHeader方法来设置Cookie标头,将会影响Session的正常工作。

 

6、保持会话

当浏览器访问一个PHP页面,而这个PHP页面又通过Hprose客户端去访问另一台Hprose服务器时,通常是不能保持浏览器到Hprose客户端访问的那台Hprose服务器会话的。那有什么办法能够将这个会话保持并传递到浏览器吗?

Hprose 1.2 for PHP中提供了这样的功能,只需要在使用客户端页面的开头如下调用就可以了。

session_start(); include("hproseHttpClient.php"); HproseHttpClient::keepSession();

 

 

7、调用结果返回模式

有时候调用的结果需要缓存到文件或者数据库中,或者需要查看返回结果的原始内容。这时,单纯的普通结果返回模式就有些力不从心了。Hprose 1.3提供更多的结果返回模式,默认的返回模式是Normal,开发者可以根据自己的需要将结果返回模式设置为Serialized,Raw或者RawWithEndTag。

 

Serialized模式

Serialized模式下,结果以序列化模式返回,在PHP中,序列化的结果以String类型返回。用户可以通过HproseFormatter.unserialize方法来将该结果反序列化为普通模式的结果。因为该模式并不对结果直接反序列化,因此返回速度比普通模式更快。

在调用时,通过在回调方法参数之后,增加一个结果返回模式参数来设置结果的返回模式,结果返回模式是一个枚举值,它的有效值在HproseResultMode枚举中定义。

 

Raw模式

Raw模式下,返回结果的全部信息都以序列化模式返回,包括引用参数传递返回的参数列表,或者服务器端返回的出错信息。该模式比Serialized模式更快。

 

RawWithEndTag模式

完整的Hprose调用结果的原始内容中包含一个结束符,Raw模式下返回的结果不包含该结束符,而RawWithEndTag模式下,则包含该结束符。该模式是速度最快的。

这三种模式主要用于实现存储转发式的Hprose代理服务器时使用,可以有效提高Hprose代理服务器的运行效率。

 

Hprose for PHP 下载:

https://github.com/hprose/hprose-php/tree/87a4e1bdc5b360096634b3a3f8d49074643624a3

 

共有 人打赏支持
粉丝 4
博文 34
码字总数 16536
评论 (0)
×
史帝文
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: