手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆
浏览模式: 标准 | 列表分类:PHP

NFS,Memcached,Tokyo tyrant实现session共享性能测试

如果不使用passport,那么把用户session存入数据库留给多个程序调用是最方便的手段了。看到这个性能测试方案,想着留下来以备案。
tokyo tyrant现在开始被人推崇了。记得以前ruby也是。为什么这么多的好东西,都是日本人发明的?真是郁闷。。。。

原文如下:

在我负责的某个项目(调查类型的网站),不久前进行了一次推广调查。因为推广邮件是在同一时间发出,所以在5分钟之内,访问量剧增,发生了15000次左右的并发业务操作,整个系统的反映速度降低很明显。

该项目使用3台web服务器,2台mysql数据库。3台web服务器间的session共享通过NFS实现。经过后来调查,访问速度骤降是session并发导致的。
 
因此,开始考虑其他的session共享方案。考虑到未来能更容易的进行横向扩展,所以计划采用memcached和Tokyo tyrant。
memcached在国内的应用已经很广泛了。Tokyo tyrant是日本人 平林幹雄 开发的一款 DBM 数据库,该数据库读写非常快,哈希模式写入100万条数据只需0.643秒,读取100万条数据只需0.773秒,是 Berkeley DB 等 DBM 的几倍,想深入了解的人可以参考:http://blog.s135.com/post/362/。
 
在论证备选方案的可行性开始之前,先做个压力测试是必须的。
 
【测试环境】
4台pc安装JMeter模拟client,web服务器一台,一台cache服务器(用来安装NFS服务,Memcached,Tokyo tyrant)。
使用4台pc安装JMeter模拟client的原因是:使用JMETER进行并发测试的时候,单台PC只能发起4100个并发线程(这个不同机器会有不同),因此要做15000的并发测试,必须4*4100.
 
web服务器上apache设置:MaxClient 256 
原来MaxClient 150 的情况下会成为性能瓶颈,改成256之后,apache没有成为瓶颈。针对某个功能做压力测试的时候,务必要做到其他环节不会成为系统贫瘠,不然测试就毫无准确度可言了。

安装NFS, memcached, Tokyo tyrant的cache服务器配置:
CPU: Intel(R) Pentium(R) 4 CPU 2.40GHz
Mem: 256M
HD: 40G
这台机器有点太寒碜了,呵呵,不过据说memcached对硬件配置要求很低,刚好可以验证下。
 
【测试程序】
因为是测试session的并发性,所以设计成个最简单的session操作流程:
1 page1.php创建session,往session写入1kb的数据,记录$time_start。
2 header至page2.php
3 page.php取得session,记录下$time_end,并计算出时间差$time_end-$time_start。
 
page1.php代码:
PHP代码
  1. <?php  
  2. function microtime_float()  
  3. {  
  4.     list($usec$sec) = explode(" ", microtime());  
  5.     return ((float)$usec + (float)$sec);  
  6. }  
  7. $time_start = microtime_float();  
  8.   
  9. session_start();  
  10.   
  11. $_SESSION['name']='abcdefghjiasdfsadflklklasdlklkjsfdkjkasdflkjsadfkljkljsdfaasdfsafdlklkjsadfkljsdafkljljksdflkflsadflkjlkjsdaflkjdsfaljklsdfajljfsd 
  12. sadflsadfljklkjsdfjlksdfaljkfjlkfslkjsadfjlksdflakkljsfdlkjsafdlkjsafdlkjlasdfkjlkjasdfljkasdlkjfsdlkjsdflkjlkasjdfljkasflkjasflkjdsaflkjlksdafklasdljksadkljfjklsdfjklfkjlsafkjlsjkldafljksljksaljklksjfdajklsdfakljsafdkljsafkdljkljsfadjklsafdasdfsfdaabcdefghjiasdfsadflklklasdlklkjsfdkjkasdflkjsadfkljkljsdfaasdfsafdlklkjsadfkljsdafkljljksdflkflsadflkjlkjsdaflkjdsfaljklsdfajljfsd 
  13. sadflsadfljklkjsdfjlksdfaljkfjlkfslkjsadfjlksdflakkljsfdlkjsafdlkjsafdlkjlasdfkjlkjasdfljkasdlkjfsdlkjsdflkjlkasjdfljkasflkjasflkjdsaflkjlksdafklasdljksadkljfjklsdfjklfkjlsafkjlsjkldafljksljksaljklksjfdajklsdfakljsafdkljsafkdljkljsfadjklsafdasdfsfdaabcdefghjiasdfsadflklklasdlklkjsfdkjkasdflkjsadfkljkljsdfaasdfsafdlklkjsadfkljsdafkljljksdflkflsadflkjlkjsdaflkjdsfaljklsdfajljfsd 
  14. abcdefghjiasdfsadflklklasdlklkjsfdkjkasdflkjsadfkljkljsdfaasdfsafdlklkjsadfkljsdafkljljksdflkflsadflkjlkjsdaflkjdsfaljklsdfajljfsd';  
  15.   
  16.   
  17. header( "location:./page2.php?sid=".session_id()."&time_start=".urlencode($time_start) );  
page2.php代码:
PHP代码
  1. <?php  
  2. session_id($_GET['sid']);  
  3.   
  4. function microtime_float()  
  5. {  
  6.     list($usec$sec) = explode(" ", microtime());  
  7.     return ((float)$usec + (float)$sec);  
  8. }  
  9.   
  10. session_start();  
  11. $name = $_SESSION['name'];  
  12.   
  13. $time_start = urldecode($_GET['time_start']);  
  14. $time_end = microtime_float();  
  15. $time = ($time_end - $time_start)*1000;  
  16.   
  17. $_file = './log/'$_GET['sid'] . '.log';   
  18. $fp = fopen$_file'a');  
  19. @fwrite($fp$time);  
  20. @fclose($fp);  
  21.   
  22. echo "$time Millisecond<br>";  
  23. echo $name;  
  24. ?>  
从代码可以看出,最后得到的time值并不是单纯的session操作的时间,session操作的时间会比这个值小。这样设计的原因是,这个值更能反映系统session并发操作的真实状况,但需确保测试环境的网络稳定,因为header函数的关系。

最后,再用perl写个简单的统计程序average.pl:
Perl代码
  1. #!/usr/bin/env perl  
  2. my $log_dir = "./log/";  
  3. my $total_times = 0;  
  4. my $file_nums = 0;  
  5. opendir DH, $log_dir or die "无法打开 $log_dir: $!";  
  6. foreach $file (readdir DH) {  
  7.     open LOGFILE, "< $log_dir$file";  
  8.     while (<LOGFILE>)  
  9.     {  
  10.         $total_times = $total_times + $_;  
  11.         $file_nums = $file_nums + 1;  
  12.     }  
  13. }  
  14. print $file_nums . " sessions\n";  
  15. print "average time is:" . $total_times/$file_nums . "\n";  
  16. closedir DH;  

【测试过程说明】
1      使用badboy先生成Jmeter脚本,然后用Jmeter进行分布式并发测试。
2      php对于使用memcached来存储session的实现已经非常简单,只需要进行如下配置:
      session.save_handler memcache
      session.save_path tcp://192.168.8.2:11211
3      如何使用Tokyo tyrant来存储session呢?因为Tokyo tyrant完全兼容memcached的client,所以配置和memcache几乎完全一样,只要改下IP和端口号就可以了。


【测试结果】
使用NFS共享session:
2000 sessions
average time is:57.2385746240701

3000 sessions
average time is:188.679696798311

4000 sessions
average time is:1139.70507353546

5000 sessions
average time is:5486.23318772304

5000 sessions
average time is:5526.97186436598

5670 sessions(说明:发起了6000个访问,却只成功了5670)
average time is:8324.00726914608

5489 sessions(说明:发起了6000个访问,却只成功了5489)
average time is:9749.52457159197

从上面的结果看,NFS支持并发能力非常有限。根本没有办法支持到15000个session。在6000个session的时候,就会发生session 丢失等未知的状况。即使在5000个session以内,虽然可以完成测试,但性能低下。
当然,这和我使用的NFS服务端的机器配置很低有关,相信优化配置,或者“采用session存储的时候,进行目录分级”可以进行一定程度的优化,但NFS的并发操作确实存在问题。
因为有另一个理由:为了方便测试,我写了个perl程序用来删除session目录下的所有文件。
del_files.pl代码:
Perl代码
  1. #!/usr/bin/env perl  
  2. my $log_dir = "./log/";  
  3. unlink glob "$log_dir/*.*";  
  4.   
  5. my $session_dir = "./session_tmp/";  
  6. unlink glob "$session_dir/*";  
  7.   
  8. my $session_dir2 = "./session_nfs/";  
  9. unlink glob "$session_dir2/*";  
当这个程序用于删除NFS目录下的session文件时,程序运行的时间明显比用于删除非NFS目录慢非常的多。

使用Memcached共享session:
5000 sessions
average time is:8.691506099701

10000 sessions
average time is:9.07290377616917

15000 sessions
average time is:9.10538846651721

15000 sessions
average time is:9.42796174685197

15000 sessions
average time is:9.43535621960958
从以上结果可以看出,memcached性能很稳定,在5000,10000,15000个session几种情况下,每个流程处理的平均时间稳定在8毫秒到10毫秒之间。

使用Tokyo tyrant共享session:
5000 sessions
average time is:8.92114758491478

10000 sessions
average time is:8.35826919078823

15000 sessions
average time is:10.7764382680262

15000 sessions
average time is:11.4394629955285

15000 sessions
average time is:8.92091128031373

15000 sessions
average time is:10.3760389963784
tokyo tyrant速度也很快。但稳定性不如memcached,可能对机器的配置要求会高些吧,或者我对tokyo tyrant配置不了解也有可能。

从测试结果看,NFS用于存储session时候的并发性能明显不如memcached和tokyo tyrant。memcache和tokyo tyrant还可以进行更大规模的并发测试。但是限于我当前的硬件,没有再进行更大规模的测试。

ok了,Memcached和tokyo tyrant的表现都让人满意,符合预期。至于要选择哪个,就得考虑其他因素了:
1      是 否需要持久存储,Memcached是不支持持久存储的,当然可以考虑使用 Memcached+DB的方式来达到“一定程度上的持久存储”,即Memcached实时保存session,在每隔一段时间(比如1分钟)将 session保存到DB,至于能否接受这种方案,得看业务需求而定了。Memcached和tokyo tyrant的其他差别,可以参考下http://blog.s135.com/post/362/等资料

2      对于这两项技术的掌握程度,整体上说,这两个技术应该都是靠得住,tokyo tyrant在日本也有不少成功的应用。但从国内来看,Memcached应用得较多,使用tokyo tyrant的话,还是要有一定的钻研精神才行。

原文请见:NFS,Memcached,Tokyo tyrant实现session共享性能测试

Tags: tokyo tyrant, session共享

老王:你们这些不明真相的围观群众啊


Shell批量修改文件内容

比如说,我想把网页文件里的foo都替换成bar,主要是利用sed的-i参数:

find /path -type f | grep -i -E '(htm|html)$' | xargs sed -i 's/foo/bar/g'

在Smarty模板里渲染嵌套数据

主要是利用include语法,

<!--{include file="_tpl.html" param=$foo}-->

然后在_tpl.html模板里接着使用
:<!--{include file="_tpl.html" param=$bar}-->,即完成了嵌套数据的渲染。

PHP中mb扩展的编码问题

mb_internal_encoding('gb2312');
mb_regex_encoding('gb2312');

需要注意的是
mb_regex_encoding不支持gbk,此时你只能使用gb2312, 类似的问题htmlspecialchars也有。

MySQL里索引的选择及取舍


给个简单的例子:按创建时间倒叙查询文章及其类别信息

SELECT *
FROM articles LEFT JOIN categories on articles.category_id = categories.id
WHERE articles.user_id = ... ORDER BY articles.created DESC LIMIT ...

那么单就这条查询而言,articles和categories表应该分别具备哪些索引呢?

articles表应该创建“user_id+created”复合索引,基本守则是先后联合"WHERE里的字段+ORDER里的字段",不过这只是最 理想的情况,很多时候,我们往往只能在"WHERE里的字段"建索引,或者在"ORDER里的字段"建索引,此时索引的选择就显得很有讲究,不应该一味的 以为只能使用"WHERE里的字段"建的索引,有时候使用"ORDER里的字段"建的索引更有效,这取决于是先用WHERE筛选后ORDER排序高效,还 是先ORDER排序后WHERE筛选高效,具体的选择取决于数据的分布情况。

另一个问题是articles.category_id = categories.id里,articles.category_id和categories.id哪个应该是索引,但就此例来说,在 articles.category_id列上索引是无意义的,因为通过WHERE或者ORDER之上的索引命中数据后,自然就得到了 articles.category_id的值,此时没有必要在它上面建索引,当然其它的时候可能需要,至于categories.id字段,肯定需要索 引了,这样才能从articles.category_id直接查询命中。

想获得UTF-8编码的数据,但MySQL表的编码是GBK的

很多人在处理这个问题时,是先查询MySQL获得原始数据,然后使用iconv或者mb_convert_encoding把编码从GBK转换成UTF- 8,其实只要在查询前SET NAMES ‘utf8’即可,不明真相的MySQL使用者们往往认为GBK编码的表在查询时只能SET NAMES ‘gbk’,这实在是一大谬误。

Tags: 围观群众, 不明真相

开发你的uc应用

这是我的开发心得,但说白了,其实很简单。只要几个简单的步骤就可以了

1、到ucenter里创建一个新的应用,设定好你的路径,还有就是接收信息的文件,默认是uc.php,还有,是否同步登录,是否接受通知。

2、保存后,再编辑,你会发现最下面有一些define的字段,COPY出来,存为uc_config.php,放到你的项目里,留着被引用

3、到其他的dz程序里把uc.php COPY出来,进行简单的修改。根据第一步的设定,以确定你的最少action是什么。

  1. 默认action中一定要有test,否则会通讯不成功
  2. 如果开启通知,则一定要有updateapps,updateapps中有两个步骤:1是把所有的应用的缓存写入uc_client/data/cache/ucapps.php(好象文件名没记错)中;2是把当前APP_ID对应的配置重写为uc_config.php里
  3. 如果开启同步登录,则需要有synlogin,synlogout两个action
  4. 其他的就看你自己了,请对应手册,比如updatepwd,rename等操作。

4、部分uc_client函数返回是html代码,请echo出来看看是什么代码,如果是script的,请直接echo,否则无法与其他app同步。这个要切记切记。(为了这个,我测试了将近三天。可恨的是DZ代码中根本没有说明,只说返回HTML代码。)

其他就没有什么了。在你需要使用的时候调用一下uc_xxx的方法就行了。

Tags: discuz, comsenz, ucenter, uc_client

PHP实现DataGrid

虽然有想过用PHP来实现datagrid,但由于php是解释性语言,而且对于数据库没有很好的长连接功能(或者说连接池吧),因此要实现datagrid的意义就不是特别大了。

但datagrid并非没有用处,如果用在网站的后台就可以简化很多操作了。或许有人会说ext不是更漂亮吗?但,这需要对JS了解的很多方可实现。为了实现一个datagrid,再去学EXT,成本有点高,因此,这个PHP的class就可以尝试试用了。     

不过,我自己一般不太会用这个东西(但并不反对在项目后台使用它),如果是我自己个人开发的话,或许会采用PHP代码+jQuery的table插件吧?

原文如下,或许可以做个参考:

最近想做一个通过PHP实现DataGrid功能的东西,这样可以直接修改数据库中表的内容,而不用开发【新增数据页面】,【编辑页面】,于是乎在网上找 了找,类似的东西也有几个,开源的、付费的都有,不过基本都是基于MySQL。由于需要连接Oracle所以从二次开发和页面样式来说个人觉得 phpMyDataGrid还是比较好上手。本篇首先介绍基于MySQL的使用方法,再简单介绍对于Oracle连接(基于sqlrelay)的二次开 发。

1. 创建测试数据库和表
SQL代码
  1. create database `guru`;  
  2.   
  3. USE `guru`;  
  4.   
  5. CREATE TABLE `employees` (  
  6.       `id` int(6) NOT NULL auto_increment,  
  7.       `namechar(20) default NULL,  
  8.       `lastname` char(20) default NULL,  
  9.       `salary` float default NULL,  
  10.       `age` int(2) default NULL,  
  11.       `afiliation` date default NULL,  
  12.       `status` int(1) default NULL,  
  13.       `active` tinyint(1) default NULL,  
  14.       `workeddays` int(2) default NULL,  
  15.       `photo` char(30) default NULL,  
  16.       PRIMARY KEY  (`id`)  
  17. )  
  18.   
  19. insert into `employees`  
  20.     (`id`,`name`,`lastname`,`salary`,`age`,`afiliation`,`status`,`active`,`workeddays`,`photo`)   
  21.     values (1, 'Ana''Trujillo',2000,45, '2005-05-13',1,1,10, '1.jpg');  
  22. insert into `employees`   
  23.     (`id`,`name`,`lastname`,`salary`,`age`,`afiliation`,`status`,`active`,`workeddays`,`photo`)  
  24.     values (2, 'Jennifer''Aniston',3500,23, '2004-10-22',1,0,0, '2.jpg');  
  25. insert into `employees`   
  26.     (`id`,`name`,`lastname`,`salary`,`age`,`afiliation`,`status`,`active`,`workeddays`,`photo`)  
  27.     values (3, 'Michael''Norman',1200,19, '2007-01-10',1,1,5, '3.jpg');  
  28. insert into `employees`   
  29.     (`id`,`name`,`lastname`,`salary`,`age`,`afiliation`,`status`,`active`,`workeddays`,`photo`)  
  30.     values (4, 'Vanessa''Black',6500,31, '2000-11-05',1,1,30, '4.jpg');  
  31. insert into `employees`   
  32.     (`id`,`name`,`lastname`,`salary`,`age`,`afiliation`,`status`,`active`,`workeddays`,`photo`)  
  33.     values (5, 'Michael''Strauss',3200,45, '2006-10-21',2,0,22, '5.jpg');  
  34. insert into `employees`   
  35.     (`id`,`name`,`lastname`,`salary`,`age`,`afiliation`,`status`,`active`,`workeddays`,`photo`)  
  36.     values (6, 'William''Brown',2300,21, '2001-03-10',3,1,10, '6.jpg');  
  37. insert into `employees`   
  38.     (`id`,`name`,`lastname`,`salary`,`age`,`afiliation`,`status`,`active`,`workeddays`,`photo`)  
  39.     values (7, 'Lucca''Normany',2800,36, '2006-10-02',3,1,20, '7.jpg');  

2. PHP程序介绍

       phpMyDataGrid主要是通过phpmydatagrid.class.php,dgscripts.js来实现的,总共加起来不到100kB, 又是一个小巧的软件。对于这两个文件就不多讲了,感兴趣的同学可以“打包带走”回去慢慢品。主要介绍该软件的使用方法,即实例 datagrid_for_mysql.php。先看一下页面示意图:

大小: 47.73 K
尺寸: 500 x 136
浏览: 1677 次
点击打开新窗口浏览全图

测试代码:

 

PHP代码
  1. <?php   
  2. include ("phpmydatagrid.class.php");  
  3. $objGrid = new datagrid;  
  4.   
  5. $objGrid->closeTags(true);    
  6. $objGrid->friendlyHTML();    
  7. $objGrid->methodForm("get");   
  8. //连接数据库  
  9. $objGrid->conectadb("127.0.0.1""root""root""guru");  
  10. //加密字符串  
  11. $objGrid->salt("Myc0defor5tr0ng3r-Pro3EctiOn");  
  12. $objGrid->language("en");  
  13. //最后一列显示的功能键,从左向右功能为“新增键”、“编辑键”、“删除键”、“浏览键”。  
  14. $objGrid->buttons(true,true,true,true);  
  15. //修改数值时产生的Form名称  
  16. $objGrid->form('employee', true);  
  17. //可检索列名  
  18. $objGrid->searchby("name,lastname");  
  19. //需要读取的表  
  20. $objGrid->tabla("employees");  
  21. //索引值用于修改数据  
  22. $objGrid->keyfield("id");  
  23. //分页显示行数  
  24. $objGrid->datarows(20);  
  25. //默认排序方式  
  26. $objGrid->orderby("name""ASC");  
  27. //显示列设置,相关设置可参考phpmydatagrid.class.php  
  28. $objGrid->FormatColumn("id""ID Employee", 5, 5, 1, "50""center""integer");  
  29. $objGrid->FormatColumn("name""Name", 30, 30, 0, "150""left");  
  30. $objGrid->FormatColumn("lastname""Last name", 30, 30, 0, "150""left");  
  31. $objGrid->FormatColumn("age""Age", 5, 5, 0, "50""right");  
  32. //自定义日期格式  
  33. $objGrid->FormatColumn("afiliation""Afiliation Date", 10, 10, 0, "100""center""date:dmy:/");  
  34. //编辑时可以自定义为<Select>模式  
  35. $objGrid->FormatColumn("status""Status", 5, 5, 0, "60""left""select:1_Single:2_Married:3_Divorced");  
  36. //编辑时可以自定义为<CheckBox>模式  
  37. $objGrid->FormatColumn("active""Active", 2, 2, 0,"50""center""check:No:Yes");  
  38. //自定义货币显示形式  
  39. $objGrid->FormatColumn("salary""Salary", 10, 10, 0, "90""right""money:€");  
  40. //将数据以柱状图显示  
  41. $objGrid->FormatColumn("workeddays""Work days", 5, 2, 0, "50""right""chart:percent:val:31");  
  42. $objGrid->checkable();  
  43. $objGrid->setHeader();  
  44. $objGrid->ajax('silent');  
  45. echo '<html> 
  46.       <head><title>PHPDataGrid</title></head> 
  47.       <body><div align="center"><br />';  
  48. //生成DataGrid  
  49. $objGrid->grid();  
  50. echo '</div></body></html>';  
  51. //关闭数据库连接  
  52. $objGrid->desconectar();  
  53. ?>  

 

3. 基于Oracle简介

对于Oracle的读取主要是把phpmydatagrid.class.php中与MySQL连接的函数修改为Oracle,本篇是通过sqlrelay(可参考http://sqlrelay.sourceforge.net/)进行的Oracle连接,当然也可以使用PHP自带的OCI8模块(效率有些低),修改后另存为phporadatagrid.class.php即可在其他程序(datagrid_for_oracle.php)中调用。以上涉及的所有程序均可在压缩包中找到。
希望对大家有用!

 

4. 源程序下载

 

 点击下载(原来的是iframe,用IE打开后就会自动下载,所以改作链接了,该链接不是我上传的,请下载后解压前主动测试。谢谢合作)

作者: Gnie
出处: {GnieTech} (http://www.cnblogs.com/gnielee/)

 

 

.NET调PHP Web Service的典型例子

一直都是关注着用PHP调用其他的soap方式的web service。偶尔看到一篇用php做web service的。有点感觉新鲜,备个案。哈哈

仅做了解。对于php做webservice,我还不知道性能如何呢。现在andot等人又在推出所谓性能超过phprpc的hprose,也不知道何时能够出来。。。

既然是用PHP做webservice,那么在看过phprpc之后,其实应该感觉用phprpc发布这些东西会更方便吧?不知道为什么不用phprpc或者hprose。。。。

纯记录,作者来自博客园的三聪,地址为:http://www.cnblogs.com/gateluck/archive/2009/08/10/php_web_service.html

原文如下:

最近一个项目由"WinForm直接访问DB2"移植到"WinForm通过PHP Web Service来访问DB2”。
(优点是php可以架在Linux上,而Linux是免费的)     
这个命题的难点不是访问DB2,而是.NET调用PHP的Web Service。对于我这个长期作.NET,之前一直以为只有.NET才可以做Web Service……的人来说,真是有点强“聪”所难了。
      但是问题还是要解决的,期限就摆在眼前呢。经过一番调查,终于有了眉目,现在分享给大家。
      
      首先要说明的,PHP服务器需要至少需要两个文件——一个WSDL文件和一个PHP文件。WSDL文件是一种机读的XML文件,用于描述WebService提供的服务和调用方法(对于.NET则可以自动生成调用代码,十分好用),php文件就是真正实现的WEB服务了。
      1)PHP服务器端代码
          1-1)TestWebService.php代码

[代码]

          1-2)TestWebService.wsdl代码
[代码]
      WSDL的代码比较长,当方法很多时,手敲代码是不太可能的。有一个巧的办法,就是也用.NET实现一个不含真正方法体的Web Serivce,然后通过http://***/TestWebService.asmx?wsdl的方法生成wsdl代码文件。
         关于WSDL文件,我要说明特别说明两点:
        (1)soap:address结点是声明WebService的地址,在部署时要改成相应地址;
        (2)一维数组的声明类型为ArrayOfType,字符串数组为ArrayOfString。如果Type不是简单类型,则Type需要另外声明。

      2).NET客户端代码
           先要添加Web引用,地址为WSDL文件的Http地址。
           调用代码(C#)
[代码]


总结: (一)PHP是一种弱类型语言,检查错误比较困难。array类型也与一般理解的数组不同,它也有类似Hashtable的用法。
          (二)PHP Web Service方法的传入参数、返回值都至多有一个,因为真正调用时的参数和返回值,都是包装到一个对象中传送的。
          (三)PHP Web Service也支持自定义类型和自定义类型数组等复杂类型,但不支持多组数组。
          (四)若返回值需要是多张二维表时,我浅薄的以为,可以传化一组字符串数组传送,格式为
                        [表1行数],[表1列数],[表1列名1],[表1列名2],……[表1列名N],[表1中按行列存放的值]
                        [表2行数],[表2列数],[表2列名1],[表2列名2],……[表2列名N],[表2中按行列存放的值]
                        ……
                        [表M行数],[表M列数],[表M列名1],[表M列名2],……[表M列名N],[表2中按行列存放的值]

                   按顺序将上面[]中的内容串成字符串数组,效率还不错,我测试10000行240列的数据,我有现成编解代码,有兴趣的可以向我索取.